-
Notifications
You must be signed in to change notification settings - Fork 113
A summary of feedback regarding the # sigil prefix #100
Comments
Um. Thanks for the effort, but... I don't really get what you intend this issue to accomplish. We've seen this feedback already. |
Repeatedly. And how many unique threads does the commitee need to see before they consider it a real issue, as that clearly hasn't happened yet. |
I was kinda hoping the FAQ would accomplish that, but no such luck so far. Still, might be worth a shot.
We do and always have considered it a real issue. But as always it's one to be balanced against other issues, which we've done, and we concluded that this was the right path. There's no number of threads which will cause the constraints to change. |
The day that ECMAScript/JavaScript died. |
@glen-84 That isn't unique threads nor unique counts; how many of those 99 or 111 etc are the same people? If you actually uniquify it to "how many unique accounts have indicated dislike of #", the numbers will be less impressive. Either way, "popularity" is not nearly as relevant as the issues listed in the FAQ. There is no tenable syntax alternative, and no sigil that's any "better" in terms of the complaints you're describing. |
@thysultan I wouldn't say ignored; more, considered and disagreed with. |
I never said that they were unique counts. Even if the numbers aren't very high, the relative numbers are significant IMO.
There is no tenable syntax alternative currently. That may change in 5-10 years. All I'm suggesting is to make room for a cleaner syntax in the future, by making this a lower-level (read: even uglier) feature and letting users transpile to that from better-looking code (code that actually looks like JavaScript, and not ASCII art). |
|
People are not merely dislike sigil, they point out a many real issues. someone does not understand it well. However, this proposal is nothing that can be done as it has reached stage 3. Everything happens for a reason. |
There are fairly strong reasons to believe that will not be the case. Few of the considerations in the FAQ are likely to change. |
Even before this compilation, it was clear to me that discomfort with Whenever I have discussed this issue with someone in person, explaining the argument in the FAQ, they have ultimately been accepting of the |
That's unfortunate. Long live TypeScript (and WebAssembly + C#?). |
It is pretty clear that the JS community looks at this proposal with disdain, so I must ask: who is this proposal for? The community clearly dislikes the syntax. Enterprise? TypeScript team clearly dislikes the syntax and they are really big in the enterprise. Why do you even allow the community to contact the team, when you just disrespectfully dismiss everything, even valid points. If you don't care about the community's voice a single bit then just straight up state the facts instead of sugar coating things and dancing around the issue. There are a ton of more appealing suggestions regarding the syntax and instead of talking about it with the community you just shut down the discussions. This is ridiculous. |
@ayylmar: I’m not participating in the committee much anymore, but having worked on public fields im still following all of the fields discussions. I think there might be some context that you may have missed. I think it’s clear that several people in the community do dislike the syntax, but it’s not clear what a viable alternative is. If you put yourself in the position of those championing private fields they’re basically left with “keep it and annoy some people with syntax, or toss it altogether and annoy some people with a lack of private fields”. It’s certainly unfortunate that many people dislike the syntax, but without a viable alternative it doesn’t seem like we’re left with anything but those 2 choices. Alternatives that many have proposed in the past tend not to make it very far down the path of exploration before an objectively blocking concern arises with them. I get it though, on its surface this seems like a simple solution: Just fix the syntax. It also kinda sucks that there’s been so many issues about this that it’s a little tricky to find the exploration of all of the alternatives that ultimately just couldn’t work. |
I'm late to the discussion, but why can't we do something like this? class Point {
// instance private, just an intuitive closure
let instance;
constructor(_x, _y) {
// class private, a private version of this to assign you class private stuff to
private this = { x: _x, y: _y };
instance = uuid();
}
equals(p) {
{ x: my_x, y: my_y } = private this;
// this works only if p is an instance of Point
{ x: p_x, y: p_y } = private p;
return p_x === x && p_y === y;
}
} javascript is inherently prototypal, not classical. The classical stuff should be 2nd class, not the other way around. Besides, this looks clean and intuitive. |
@doug-numetric |
@ljharb Thanks for the response. I see the need for class Point {
// class private
private z = 0;
// instance private, just an intuitive closure
let instance;
constructor(_x, _y, _formatter) {
// class private
private this x = _x;
private this y = _y;
private this formatter = _formatter;
instance = uuid();
}
equals(p) {
// this works only if p is an instance of Point
return private p x === private this x && private p y === private this y;
}
print() {
return (private this formatter)(private this x, private this y, private this z);
}
}
const p1 = new Point(2, 4, (x, y, z) => `<${x}, ${y}, ${z}>`);
p1.print(); // <2, 4, 0>
const p2 = new Point(2, 4, function(x, y) { this.x = 0; return `<${x}, ${y}>; });
// I suspect this should throw a TypeError "Cannot set property 'x' of undefined"
p2.print(); The destructuing shorthand is just really handy sugar, which I like as this can get verbose. |
See the FAQ.
Separately, no, that's not. In JavaScript as it stands, a given function doesn't see different values for a closed-over variable depending on how the function is invoked. (Keep in mind that class methods are shared; there's not a separate copy created for each instance.) As such the only consistent semantics for this syntax would be for it to have the same value for all instances of the class, just as if the declaration had occurred outside the class. Which I think is not what you want. |
I've finally been motivated to sign up to github. I've been reading issues and such around several TC39 proposals because I'm in the process of helping my company figure out how we want to approach es going forward (a former employee enabled stage 0 plugins in Babel and no real discussion of risks ever happened).
Even with that, I disagree with the claim that # is significantly better than declaring a private field as private and then accessing it like any other field (just as in Java and other languages). From what I understand, it looks like you are avoiding implementation of privates using WeakMaps? Used properly, I have yet to see a case that breaks. As for the example in the FAQ, it has a flaw that's easily corrected:
I didn't bother refactoring the entire sample code to use getPrivate vs. directly accessing members of the privates object in every instance, but it's enough to demonstrate that the reasoning in the FAQ isn't entirely convincing. The important part is that you should never leak the references of any objects stored in the privates WeakMap. Of course, I know you can't do
Basically, assignments to a private field go from As far as I can tell, the primary motivating factor behind Personally, I'd probably look into something like TypeScript before actually using # in any real code to declare/access private fields. Primarily I ended up here because I had to just now refactor some code involving the use of |
Instances (public and private) have been stage 3 for awhile; statics only reached stage 3 this week. Separately, typescript doesn’t have truly private fields - nothing ensures their privacy at runtime. |
From what I've read, it looks like private/public, static, and decorators are kind of merging together due to the fact that decorators apparently need knowledge of private members. Considering the demand for decorators, I wouldn't be surprised if the motivations for implementations that are spec compliant with private only happen because the contributors really wanted decorators but had to deal with this version of privates because they had to in order to be fully compliant. I don't know much about typescript, but I wonder if the lack of true privacy has to do with the fact that WeakMap itself is fairly new and not everyone can work only with modern browsers. |
I'm really glad to see how @glen-84 grab issues together (I'm author who create one of that). In my humble opinion, it's developer experience. Community want to use Committee should understand, that, you do it in your "own" way. It's truly egoistic way. All enterprise languages like Java, C#, TypeScript, also PHP use It's a big problem to implement proper public / private access to field without using You are talented engineers! You add many amazing features to JavaScript, and you can do it properly too (under the hood) without losing semantic. Some of people in issues provide possible examples for using |
General feedback:I gave slots a serious test on Monday (Chrome 67). I found they caught dumb typos and it was great to have a list of (private) fields rather than having to squint at the constructor code; I even warmed to the But, I've got into the habit of destructing the properties I need at the start of a method:
It's ergonomic (one Unless, I've missed something, slots break that. Doing it manually is cumbersome and uses a heap of screen estate so I was slipping back into So my feedback is that slots have rolled back usability and manageability of the code. But that can be fixed with follow-on proposals: allowing access to slots as just Other than that, I found them far less horrible than they looked, and have been itching to use them in production code. |
@fuchsia, thanks for the feedback. I think we likely will want to allow writing @pumano, please see the FAQ. It turns out that, yes, this is the best solution for JavaScript, in the opinion of the committee. Our constraints are unusual, especially the lack of a type system. The other solutions people have suggested have all seemed unacceptably bad in one way or another. |
The renamed destructure seems like a great follow on. To avoid variable name confusion, it’ll probably be necessary to force the rename |
@ljharb @bakkot
To both of you: Is having this implementation of private fields really worth promoting |
This is not true. There is a fairly straightforward and precisely equivalent desugaring using WeakMaps, though it requires some non-obvious care to get calls right. See the babel transform for an implementation. |
Class can definitely do things that can’t be done otherwise; extending builtins, in particular. |
Simply put, I'm arguing that the contents of the shipping container are more important than the container. You, seeing the container as more important feel it's perfectly fine to modify the contents. |
@ljharb I don't care about how you read the spec, I just want TC39 guys tell me and the whole community, why all these issues are unimportant:
|
@hax Realizing that your question was for @ljharb, I still want to say that although I have made my position clear, I can see both sides of this debate. Can you? Opponents of this proposal are naturally very focused on its downsides, but classes 1.1 has a lot of downsides too, including some that are worse IMO than any downside of this proposal. Since this thread is about syntax, I'll say that IMO the classes 1.1 syntax seems illogical and inconsistent compared with this proposal. With this proposal, you only have to learn the meaning of OTOH, I can see how classes 1.1—especially if public instance property declarations were added to it—could actually be a viable alternative to this proposal, and I can see why some people prefer its syntax... After the initial learning curve, the syntax does make sense and doesn't lead to false expectations like thinking you could access a private name dynamically (e.g. I'm sure there are others, especially including committee members, who could make plenty of other strong arguments about why this proposal is overall better than classes 1.1. I don't think anyone is saying that it's perfect or that its downsides are unimportant, just that on balance it's still better than the alternatives. |
Wrong model. These are regular variables in every sense of the term. The only thing that's changed is that the lexical scope of the class declaration now provides a function-like container to hold them. In other words, "Where variable declarations are concerned,
Please explain. Everyone already understands that
It's a new operator. Of course it would need explaining. But it's worth the gain in expressiveness. Also I thought of a solution to the shorthand syntax problem that would put both instance properties and instance variables on the same playing field by omitting the need for I want it to be clear that while class-members is a fork of classes-1.1, it diverges from it in significant ways. The fact that it is still open for modification means that any such concerns TC39 has for its design and/or limitations can still be addressed. It's main benefits are that:
Beyond this, it has the same basic capabilities as the existing proposal. Despite my desire to avoid it, even public-fields can be added to the proposal without difficulty. |
You have repeatedly insisted that top-level, non-static declarations inside a class should only define things that go on the prototype. And yet you make an exception for the instance variable declarations in classes 1.1 and class-members (var/let/const). I realize that instance variables are in no way properties, but at least regarding the syntax your argument is inconsistent. In this (class-fields) proposal, |
@mbrowne I agree there are still problems in classes 1.1 or @rdking 's fork. As I said before, how could you expect a proposal only have several months (or days for @rdking 's case) to discuss can just be perfect? Actually I think classes 1.1, @rdking 's fork and private symbol proposal are all better than this proposal even in current state using the same logic of "balance". And consider current proposal has been discussed several years and still so fuzzy, I also believe there is no way to fix current proposal, but alternatives still have many possibility to get better. For example, a criticism to private symbol is it miss the brand check. Actually it could be easily added if we have time and space to investigate. Of coz many could just disagree. Many time, I feel they disagree arbitrary. Anyway, the problem is how could we decide which opinion is much "correct balance"? This is a very hard question and I don't have the answer. So I think @Igmat collecting feedbacks from community is the only way we can do now, and I decide to follow his way, though I was very unwilling to do that because it could cause break between the community and the committee. |
Actually public field is also new syntax, and you eventually have to learn that the meaning of And you also need to learn The worst part is, the slogan "# is new _" is too attractive and the superficial usage of it in React make the programmers lose the alertness of such a new feature which have many consequences for real world engineering (especially of OOP). |
@hax the I'm still not sure what "OOP consequences" you mean. The ability to encapsulate functionality such that it can't be tapped into, reflected on, or overridden is a very important part of OOP. |
Ok. I get your point here. Let me make my argument more clear. Any declaration in a class that begins in the same way as a method declaration (
It's following this approach that the |
@rdking You're nitpicking, and other people will see it the opposite way. The field syntax includes the
There's nothing that makes it immediately clear that it's per-instance. In fact when I first saw it, I thought it looked like a private class-scoped (static) variable. |
@mbrowne Saying I'm nitpicking is a meaningless jab. The devil is in the details. If you're not willing to scrutinize the details, you'll miss opportunities. The
Strawman argument again. Other OOP languages are class-based, not prototype based. They have metadata for the class template. All class properties are automatically on the instance because there's no other place for them to be! In prototype-based languages, the prototype is the template. My argument isn't as weak as you try to make it out to be. Look at how
Notice that declarations use keywords when the declaration doesn't get applied directly to the prototype? That's the precedent for my argument. There's no way that matching pattern in the existing language constitutes a "weak argument".
I might have to relent on that one, but I'm not so sure. Currently no definition in the class declaration exists without being instantiated unless it uses the |
Really "without explanation"? Really "without needing to learn anything"? I hope you could do test in the wild. Find someone who never heard class field before then throw this code to them: let a = 1, b = 2;
class Test {
a = 3;
b = a + 1;
}
const test = new Test();
console.log(a, b, test.a, test.b) Let them tell you what result they expect. Do be ostrich, do it yourself!!!
Yes let the developers who never see class field before read the code I provide and try to understand it and tell you the truth. For those already know or used class field (especially the react users), throw this one to them: let a, b;
a = [1,2,3];
[b] = a;
class Test {
a = [1,2,3];
[b] = a;
}
const test = new Test();
console.log(a, b, test.a, test.b) Let them tell you what result they expect. If you don't like do the real world test, no problem. I will do it in Jan 6th, 2019. There will be 500+ china js programmers in the D2 conference, and I will report the result to you.
They'd better never learn the tragic term which convey the wrong information of similarity of public/private.
Yes, why they need to know? So let them only know it when they shot by footguns. |
Here is the only useful use case discussion part.
So what you mean is your use case is iterating data properties only outside of class? Could give a real world code sample for us to understand the real concept model of using it? What data properties (actually Note, we also heavily use object destructuring. You should notice that it have different semantic with object spread, Object.assign, Object.keys, etc.
There is also Reflect.ownKeys, Object.getOwnPropertyNames, Object.getOwnPropertySymbols..., don't forget the old So I very doubt we can inspect an object in a easy way and solely rely on the usage of special API. We'd better check the real world use case and find what the real concept model they are using, instead of saying we should follow any inconsistent object reflection functionality in classes arbitrary. |
@ljharb And I suspect the usage of reflection of own props of class object (not plain object) may essentially collide the encapsulation idea which is why private field exists. Consider an exist class which (have to) use data properties to store internal state now. With private field available, the author could decide to hide some data properties, use private field instead. And your assumption of iterating of own props is must to have is just conflict with it. If anyone rely on iterating all data properties outside of the class, such class could never use private field. We should realize there are two different usage of classes:
Private field is based on 1, and public field may based on 2. These two may have essential conflict. And current proposal just bundle them together and the duality of syntax and name (both 'field') just make the situation even worse. |
(Referring to your first code sample) that would not be a fair survey. For people who have never seen or used class fields before, the first step should be to show them working code, not invalid code that doesn't even run successfully. At the very least, show an example with basic, correct syntax (e.g. |
How could a code sample be absolute fair?
The sample code is valid and runnable in latest chrome (with flag enabled) and babel 7. But I guess you mean we should first introduce a "good example" to teach them what's the syntax designed to behave. I don't necessarily disagree this way. That's why I also provide the second code sample for those who think they already know public field well.
The code examples are totally "syntax correct" as public field proposal. If you think it's a "broken syntax", you should agree current public field have a "broken syntax". 😜
I guess I know what you mean. But for the same reason, if you introduce public field motivation/syntax/semantic first, you also bias people's expectations --- Many people will become blind to the gotchas until they was caught in real world programming (I just found this is why they are called GOTCHAS 😜 ). As my observation, when you tell a programmer what intend to work, they will try to decode the underlying logic (for example, transpile the code in their mind) and follow your design by default, even your design was broken. This is what is happening in dealing with public fields --- auto transpile Even worse, most programmers have trained themself always follow the rule: if the result is not you want, that's your fault, and you should RTFM. Such rule is good for practice, because you can never change the language, you eventually have to swallow it. But it also means the programmers are very tolerant and insensitive to the design flaws of the language. And someone even refuse to admit it's a flaw, and argue that "it's by design". /* Here I give you an example of PHP which maybe a little bit off-topic: In PHP, you can write That's why I provide the first code sample, let the programmers use their original intuition to investigate the syntax.
Yesterday I gave a speech about class fields in my company, and something interesting happened. A talented programmer in our React team see my slide of the first code sample and told me the result have to follow class field semantic or it doesn't make sense (this is just the reaction of "it's by design" I mentioned before). And my next slide is: class HelloWorld {
name
greeting = `Hello ${name || 'world'}!`
constructor(name) {
this.name = name
}
run() {
console.log(this.greeting)
}
}
new HelloWorld().run()
new HelloWorld('hax').run() This buggy code have the result of two time See? He is a very good JS programmer (in the top 10% I believe) and obviously know many details about the semantic of class field proposal. But the explanation is wrong. When I pointed out We also discussed, in real world what will happen if you want to fix the code but with wrong understanding about the reason of the bug, but I have written too much again, so leave this part to you. Hope you see my point. Yes,
All programmers attending the discussion in my company agreed the answers are three NO. |
@hax Could we continue this discussion in a new thread? This thread has become so long that it's difficult to navigate...348 "hidden items", and you can't even expand them all at once making it difficult to look up comments from a few weeks ago. I created a new issue here: If that works for you then I will respond to your latest comment there. We could CC everyone who has been recently participating in this thread. |
@mbrowne That will be great! |
@douglascrockford Have you taken a look at this proposal and the high amount of votes against it? It might be a worthy contender for the bad parts. Besides syntax dislike that some people have with the private portion of the proposal (which is of no consequence to a pragmatic engineer), the proposal actually has fairly bad technical issues waiting to chop someone's foot off:
|
Other feedback:
The TypeScript team are not fond of the syntax either.
My suggestion to rename the proposal: tc39/proposal-private-fields#72
(the idea is mainly about making it a lower-level feature, and making room for a cleaner syntax at a later date)
@littledan @bakkot @ljharb – I apologize in advance, as I know that you must be thinking "Oh g*d, not again!", but I just wanted to put this all in one place, and allow the community to share their opinion in the form of reactions. It would be great if you could keep this open for a while (30 days?), or perhaps even indefinitely to prevent other users from submitting even more issues on the same topic.
To the non-committee members reading this: These proposals are now at stage 3, so it's unlikely that a syntax change will occur, but please feel free to up-vote this issue if you feel that the sigil (
#
) prefix is not a good fit for the language, or down-vote the issue if you believe that it's perfectly acceptable.The text was updated successfully, but these errors were encountered: