Closed rdking closed 5 years ago
A part from a few points, I kind that article good:
Static Fields on the Prototype
really? :thinking:this
to the methods it will still work.Break in Access Expectations
Other than using eval
, if you need to dinamically access some private fields you can save them in an object and than save that object in a private field. That would also work with enumeration.Side note:
You could add a link to https://babeljs.io/repl/build/master
and write "enable the stage-2 preset in the left sidebar and try class fields yourself!" so that people can actually see what you are saying.
the static-class-features proposal seems intent on having static fields live on the prototype
Yeah, I don't know what this means either. Static fields are proposed to live on the constructor, just like static methods currently do.
2. To be really fair, it should be noted that if a Proxy carefully provides the correct
this
to the methods it will still work.
@nicolo-ribaudo are you kidding? Some Proxy usages, that aren't Membrane
or even Membrane
-like, require providing proxy as this
and not real target, so article is really fair describing this.
Or you're trying to insist that such usages are improper, are you?
I should have used original instead of correct. If a Proxy provides the original this
it will work, otherwise it won't.
@nicolo-ribaudo
new Proxy(target, {})
, it's fair enough to say current proposal by default break Proxy.this
.The main usecase I can think of proxies are: 1) Membranes 2) Tracking how an object is used 3) Tracking internal dependencies in the implementation of a class
Two of these work with private fields. I agree, we shouldn't say "Proxies are 100% compatible with private fields" because it isn't true, but it should be noted that they aren't always broken.
Thank you all for the input so far.
I've made the adjustments suggested here. One thing I noticed is that no one has raised any issue with whether or not the document is a "fair" representation of the proposal. I'm planning on injecting some more code examples into the document next. I don't know how much help Babel.io will be for this since it cannot run the examples. Also, for as nice as it is, it doesn't protect private fields from eval
access, but that's just a gripe of mine. @nicolo-ribaudo, couldn't you fix that by wrapping all of the class-specific elements in a self-executing function that returns the class?
In either case, I want to keep the examples as small as possible. This article is already an 11 minute long read.
@rdking
I don't know how much help Babel.io will be for this since it cannot run the examples.
It can. Just check the ☐Evaluate
. But it keeps evaluating in the browser directly as you type, not so friendly. Maybe you can use https://jsbin.com along with babel-standalone.
Ok. Just added Babel.io examples for the Proxy issue and the Public fields vs inheritance issue.
This summarized several points in a way that was not too technical for me to understand. Thanks a lot. I feel like a lot of the discussions here become too technical and hard to follow (thus hard to participate), and that a handful of the less technical questions get overlooked. I thought the article was fair and informative.
Just added Babel.io examples This was definitely a helpful addition. (I was going to suggest this especially for Set vs. Define, which is much clearer now with the example.)
Overall, I think it's a very useful summary of many of the considerations of this proposal, and while it's easy to read between the lines and see that the author (you) is not happy with the proposal in its current form, I think it's quite fair.
I know you're trying to keep the article short, but one addition that I think would be worth including is a bit more discussion about syntactic consistency. You mention in passing that "There is no equivalent [] syntax for this.#x", but I think it would be good to spell out the consequence that this.#x != this['#x']
. And also that you can have both this.x
and this.#x
. This is both a good thing and a bad thing...good because it guarantees that adding a new private field is always a non-breaking change, bad because it's potentially confusing and is inconsistent with existing syntax. It's an important tradeoff, and IMO the name collision issue is even more important—regardless of which side you're on—than whether or not you can access private fields dynamically.
Regarding this:
It’s only a guess, but I’d wager that class was released without data properties due to an issue with prototype-based data properties.
I highly doubt that was the reason, but you say it's "only a guess" so I guess it doesn't matter so much. I'm not sure where to even try to validate this...I guess the old ESDiscuss discussions are probably still available on archive.org. But just to clarify what I mean, first of all this assumes that putting data properties on the prototype is what the committee members (at the time) would have preferred to do if there weren't issues with doing that, which might not be true at all. And more importantly, there were probably lots of issues to be discussed about how to implement public and private data members just like the tricky and often controversial discussions there have been about this proposal, and it was only because of the "maximally minimal" approach that the committee was actually able to reach consensus and move forward at that time. Clearly, data properties were cut as part of that "maximally minimal" evaluation process.
Editorial notes:
@mbrowne I've made adjustments. Let me know what you think.
In truth, I'm trying to make this article a realistic, coherent, easy to understand document that explains the current proposal without siding one way or the other. That you can read between the lines and see my irritation is unfortunate. Short of reducing "the bad", I'll take any reasonable advice about how to further bury that "between the lines" understanding.
@rdking The updates are good.
In response to your most recent comment...well, obviously someone who thought this proposal was the best option wouldn't use "The Good, the Bad, and the Ugly" as their premise, but I actually liked that as a literary device and I don't consider it a fatal obstacle to writing a fair and balanced article. But here are some quotes from the article that I think make your opinion obvious, especially when taken together:
But ugh! That #!
Would you find it so ugly if JS—with class fields—were your very first exposure to programming? Even if yes, would every new programmer have that reaction? This is obviously a very subjective thing, and your article basically assumes everyone will have the same reaction. As a professional developer with experience in several languages, I understand why people find the syntax ugly but even so I never had such a strong visceral dislike of it. Still, your audience is the average JS developer and people can easily make up their own minds on this. So this is my most minor criticism and I don't think it would really be a problem to leave this part of the article as written.
I hate to put it this way, but by itself, “the bad” could easily be an article or two on its own. It should be noted that TC39 is fully aware of each of these issues. Admittedly, each one is small and easily dismissible by itself. I’ll leave it to you to decide whether or not the collection of these issues is worth what “the good” will bring.
This invites the reader to make up their own mind, which is good, but as a whole, this paragraph is pretty leading...
There are indeed a lot of issues with this proposal, but there are plenty of issues with alternative proposals. And a comparison just of the quantity of issues isn't the only factor; the severity of the issues is critical. It's clear that in your opinion, this proposal is the clear loser compared to alternatives, but that's a matter of perspective. While one could certainly write long articles just about the problems with this proposal, one could also write long articles about its benefits and ways in which it's superior to alternatives.
If you’re finding yourself getting depressed over the problems that plague this proposal
Doesn't take too much "reading between the lines" to see your opinion showing through here ;)
BTW, while I was re-reading the article I noticed that the "Private/Public Name Confusion" section is kind of confusing. I assume that you're talking there only about forgetting to include the sigil when accessing a property, not when declaring it, but it's written in kind of an ambiguous way.
@mbrowne
Would you find it so ugly if JS—with class fields—were your very first exposure to programming?
My first exposure to programming was with AppleSoft Basic, and yes, I found some ugly but exceedingly useful things about that language as I learned it (peek, poke, chr$, etc...). But I was 7, and probably very different from most first-timers today. The document itself is written to target existing JS developers, people who have an opinion about what should and shouldn't go into the language they're already using. Among developers like that, the sigil is a point of varying degrees of dislike, consistently.
This invites the reader to make up their own mind, which is good, but as a whole, this paragraph is pretty leading...
I think I might pull the first sentence and maybe re-word the last. The problem with the last sentence is that it raises a question that needs to be raised, but there really isn't a way of raising that question without implying an answer.
Doesn't take too much "reading between the lines" to see your opinion showing through here ;)
Yeah, I was writing that at around 2am. I think fatigue probably broke my filter.
I assume that you're talking there only about forgetting to include the sigil when accessing a property, not when declaring it, but it's written in kind of an ambiguous way.
It's written that way intentionally. While it's not as easy to miss the sigil in a declaration, it depends on how you write the declaration. If by some rare chance you do miss that sigil, your code will break in weird places. If by some happenstance you add a sigil in a declaration that shouldn't be there, you can also cause issues. It's not just a problem for access. It's just that it's less likely for declarations. In either case, you have to keep on your toes about things. I'll still consider re-tuning it.
@mbrowne Ok. I've updated yet again. This should be considerably more neutral wording in those key locations.
if you need to dinamically access some private fields you can save them in an object and than save that object in a private field. That would also work with enumeration.
That means unfortunately we're probably going to see people using #
to create a private namespace:
class DOMPointReadonly {
// holds all private stuff
#_ = {
x: 0,
y: 0,
z: 0,
w: 1,
};
constructor(x, y, z, w) {
this.set(x, y, z, w)
}
set(obj) {
Object.assign(this.#_, obj)
}
get() { return { ...this.#_ } } // maybe not so bad here
get x() { return this.#_.x }
get y() { return this.#_.y }
get z() { return this.#_.z }
get w() { return this.#_.w }
}
instead of something that would be better:
class DOMPointReadonly {
#x;
#y;
#z;
#w;
constructor(x, y, z, w) {
this.set(x, y, z, w)
}
set(obj) {
Object.assign(this, obj, #) // we'd need a way to pass the access helper to code which otherwise has only public access to our object.
}
get() { return {# ...this } } // we'd need a way to specify spread of private properties (yes, properties, with descriptors)
get x() { return this.#x }
get y() { return this.#y }
get z() { return this.#z }
get w() { return this.#w }
}
And what about private methods?
class Foo {
foo = 'foo'
#_ = {
privateMethod() {
console.log(this.foo)
},
}
publicMethod() {
this.#_.privateMethod.call(this) // ugly
}
}
let f = new Foo
f.publicMethod() // "foo"
Oh wait, that was pointless, I can just make an arrow function on the private property.
...But this means the arrow functions (or privateMethod
in the above example) will be duplicated across instances.
So if I have 1000 instances, I'll have 1000 * n
functions where n
is the number of private methods that the class has, so for a class with 10 private methods, that's 10000
instances of Function
.
That would not be good. Or did I miss how private methods work?
How often would you need to enumerate or dinamically access private methods? Anyway, let's move the discussion somewhere else since this thread is about the blog post.
All the time. Just because they're private doesn't mean I want to lost the flexibility I otherwise have with regular objects. Imagine an ArrayReadonly
class. I'd like to loop on the private properties, and push and pop privately as needed to convey changes to the public.
I'm not sure if we need a new thread to discuss this idea. It's already been addressed several times in this issue tracker.
In its present form, the article is complete. Since no one is offering new suggestions for improving the article, I'm closing this thread.
Following the articles by @Igmat & @hax, and taking into account the complaints of a lack of "fairness" by @slikts, I've written a new article on Medium.com that makes a new attempt at calling for more public attention to this proposal. All I really want to know is:
All opinions are welcome, but opinions fitting one of those 2 items will help me write a better article later.