8 ms·
The rationale for the "#" syntax is that it makes it clear that the field is NOT an object property. This is an important distinction because you can do this:
by __ryan__ 8y ago
The rationale for the "#" syntax is that it makes it clear that the field is NOT an object property. This is an important distinction because you can do this:
class Example {
#myVar = 100;
getPrivateMyVar() {
return this.#myVar;
}
getLocalMyVar() {
return this.myVar();
}
}
const example = new Example();
example.myVar = 200;
console.log(example.getPrivateMyVar()) // 100;
console.log(example.getLocalMyVar()) // 200;
I agree the syntax is terrible. But you need to be able to distinguish between the own object property myVar and the private field myVar.
- Illniyar 8y agoAccess modifiers, as the name suggest, are an accessibility feature not a scope feature (like let). example.myVar = 500 should throw an access error. You don't need to distinguish because you shouldn't be shadowing private variables.
- __ryan__ 8y agoNot as far as the spec is concerned. They decided that private variables should be completely scoped to the class. "Having a private field named x must not prevent there from being a public field named x, so accessing a private field can't just be a normal lookup. This is only an issue in JavaScript because of its lack of static types. Statically typed languages use type declarations to distinguish the external-public/internal-private cases without the need of a sigil. But a dynamically typed language doesn't have enough static information to differentiate those cases." [0] There are also performance concerns to changing the lookup logic without the sigil. More info in the link. 0: https://github.com/tc39/proposal-class-fields/blob/master/PRIVATE_SYNTAX_FAQ.md#why-isnt-access-thisx https://github.com/tc39/proposal-class-fields/blob/master/PR...
- dotancohen 8y agoI still don't see why this is an issue in Javascript. PHP, the canonical hate-it dynamically-typed language, does not have this issue. Sure, you say, that's because in PHP a public property and a private property cannot have the same name. Correct. Why is this a requirement? What problem is this trying to solve? In e.g. older Python we would use the convention of a leading underscore to indicate that a property is private, even if technically one _could_ access it publicly it was understood that is a bad idea to do in practice. It's not a security issue - in every language one could read the "private" properties by some method or another. Reflection, for instance. Or, back to PHP, by casting the object to an array (I did mention that PHP is the canonical hate-it dynamically-typed language).
- Klathmon 8y agoI really recommend you read over the FAQ that is in the proposal at [0], it answers most of your questions. The problem is that it seems a "private by convention" system isn't private enough for many library authors, who are finding their private internal methods being used regardless, and then after some time becoming ossified leaving the maintainers in a tough situation. Support the "private" interface even though they shouldn't have to to avoid breaking a significant number of users, or break the "private" interface and leave many developers with code churn. Regardless of where fault lies (often times it's one library using the private interface of another library, and the developer gets caught in the middle), this is a bad thing, so people began workarounds like complicated closure systems or weird-looking interfaces which emulated true private fields without having support for them. This started becoming popular enough that it was decided that adding them to the official syntax would be better, and unlike in PHP or other languages, there is no way around it here. Serializing or casting the object doesn't expose private fields, and there is no reflection methods or anything that would allow it. They are truly private. I personally share your feelings that this isn't an issue that needs solving (i'm of the opinion that the lack of easy truly private properties had a non-zero impact on the rise of javascript, and the ability to tweak private interfaces in your code is a net benefit, even if it gives developers rope to hang themselves with), but the pain felt from it is real for many, and the workarounds they were using were not only slow and difficult to use and maintain, but also very hard to understand, and this alternative is a much better solution in my opinion. So while I most likely won't be using them, I reluctantly support them being added to the language. [0] https://github.com/tc39/proposal-class-fields/blob/master/PRIVATE_SYNTAX_FAQ.md https://github.com/tc39/proposal-class-fields/blob/master/PR...
- Klathmon 8y agoIf `example.myVar = 500` can throw errors, then is the private field really private? Since now it's existence can break the public interface, and changing it to `myOtherVar` during a refactor can break existing code. That removes a major benefit of private fields (which is to be able to change implementation details without breaking the public interface) I don't think anyone really loves the syntax, but there doesn't seem to be much of a better way of doing it.
- franciscop 8y agoWhat happens if you do `example.#myVar = 500`? Does it throw an error? Wouldn't it be the same situation?
- Klathmon 8y agoas of right now, `example.#myVar` isn't valid syntax, which is the reason that the # sigil was chosen. It's not possible to have current code that works like that, so defining new properties for that code (that it can only be used inside the class as a private field) isn't breaking anything. In other words, outside of the class implementation, `example.#myVar` is always an error, regardless of the existence of a private field or not, and it will always be an error with or without this proposal. And inside the class it's only legal if the private field was defined in the class.
- __ryan__ 8y agoThe difference is that when you type example.myVar = 400 you are setting a property names "myVar" on the object to 400. When you type example.#myVar you are trying to set example's private field to 400. The intentions are distinct and it is not costly to determine at the call site what you're trying to do.
- earthboundkid 8y agoWhat if I have private values I want to access programmatically? Ie. fields = ['#foo', '#baz', '#bar']; fields.forEach(field => { this[field] = frobnicate(field) }); ?
- _pmf_ 8y agoAlso, the # is traditionally the "protected" modifier in UML.
- VMG 8y agoUML should not factor into this discussion
- coldtea 8y agoAny established prior convention can factor into such a discussion, even if it doesn't concern javascript (and since it didn't have private properties before, all established prior conventions will be from other languages and/or domains).
- VMG 8y agoThere are many obscure systems out there (yes, UML is obscure). If you try to consider conflicts with all of them you cannot do anything.
- bad_user 8y ago> is NOT an object property But it is an object property, just like everything else attached to "this". That "this.foo" is not "this.#foo" that's because "foo" is a different key than "#foo".
- Ajedi32 8y agoIt's not merely a different key; it's a completely different _type_ of key. I'm not sure how it's implemented internally, but `this.#foo != this['#foo']`.
- bad_user 8y agoObjects in JavaScript are just maps, so technically speaking if they disallow "this[#foo]", it's just a cheap trick.
- Ajedi32 8y agoThey don't disallow `this["#foo"]`. It's a completely different thing than `this.#foo` though. Think of it like this: this["#foo"] = "Value A" this.#foo = "Value B" console.log(this["#foo"]) //=> "Value A" console.log(this.#foo) //=> "Value B" That's why people are saying that `this.#foo` is not an object property. You can think of it like one if you want, but it's not really the same thing.
- simias 8y agoI only write a tiny bit of JS (and I mostly hate it to be honest) but what's the reason for this difference? Why not make them object properties to make the language more regular? I know this is very non-constructive but reading through these threads and these proposed improvements to modern JS the expression "polishing a turd" pops up in my mind repeatedly. That people chose to bring this thing out of the browser to use as a general purpose language is rather baffling to me. I can't wait for WebAssembly to become more mainstream, then I'll be able to archive my little knowledge of JS deep into my brain, alongside Perl and TCL. </nonconstructive rant>
- throwaway427 8y agoFrom the syntax proposal: > Having a private field named x must not prevent there from being a public field named x, so accessing a private field can't just be a normal lookup. Why do classes support public/private fields of the same name in the first place? This seems fraught by nature?
- __ryan__ 8y agoIt's more of a side effect that the class can define these properties of the same name. The real goal is that in the following example, the private property #x is not affected. class A { #x = 100; } const a = new A(); a.x = 200; On top of this, you should be able to define private variables and methods in derived classes without interfering with the base class private properties: class A { #x = 100; getA() { return this.#x } } class B extends A { #x = 200; getB() { return this.#x } } const b = new B(); b.getA() // 100 b.getB() // 200;
- syspec 8y agoThis example seems like something you shouldn't be able to do. Now you have 2 private '#x' properties with unique values. It's very surprising. Intuitively, you would expect the subclass to essentially be saying "my version of this variable is equal to 200, not 100". Then both calls should return the same result (200)
- throwaway427 8y agoAnother comment in this thread noted this is how Java works. I very much agree with you, but I guess there are different interpretations of how this should behave.
- __ryan__ 8y agoThe spec (and the committee) has defined "private fields" to mean that anything outside of the defining class (including subclasses) should have no knowledge of them. If your subclass needs to know about the property, make it "soft private" by prefixing it with _.
- hiccuphippo 8y agoBut you could do the same with "_". I think the feature is good but couldn't they find a different character than one used for comments almost everywhere else?
- iraldir 8y agoWell a lot of characters are already taken. Starting with _ is already valid JS syntax so it would break existing code. @ was a popular symbol for this but got taken by decorators.
- arrty88 8y agoWhat ever happened to using double underscore for private fields