Closed friendlyanon closed 6 years ago
This has been discussed at very great length. Please see e.g. the FAQ for private fields.
There are a couple of goals that this proposal is taking into account that inform the syntax:
this
as the receiver. For example, you could have an equals
method which reads private fields of an argument which is of the same class.this
, there is an explicit lexical this
. It's hard enough for people to debug this
as it is--adding more places where it comes up implicitly could make it worse.It seems like the syntax proposal you made above doesn't quite meet these goals. I don't see a way to refer to other receivers, and the use of this
seems implicit.
About aesthetics: I think people will get used to seeing #
over time.
@bakkot the part regarding why private
was not used just says that other languages also use the keyword private
for private fields and the access is done with this.x
. I think we are far past the point where it should be dabated that despite JS looking like a mish mash of many languages, it very much is its own language, which I might add does not justify ugly syntax, however.
@littledan
But yes, personally my main issue is that very much alien syntax.
If the main issue is that the syntax is new, that's not an extremely strong argument. After a year or two, #
may become normal-feeling.
This is way much better than #, but still I think private properties are not needed in JS.
+1
I believe that there should be an explicit distinction between accessing private and public fields. JS is moving in the direction of providing more explicit ways to express one's intentions.
There is a distinction. One has #
and the other doesn't.
Imo, accessing private
methods not from this
but from private
– it quite good and elegant solution.
It just clearly indicates - you cant access private methods of that
, cos there is no this
.
In the same time - private
must be bound to the same context, as... context, and...
this is already a source of enough confusion in JS; we'd prefer not to make it worse. Also, it's a major refactoring hazard: it would be surprising if this.x had different semantics from const thiz = this; thiz.x.
New context sensitive variable will just double happiness from the debugging.
The same way classes are sugar syntax for prototypes, the way @friendlyanon presents it:
class Test {
private x = 0;
private myMethod(value) {
private.x = value;
}
myPublicMethod() {
private.myMethod('test');
}
}
It can be sugar syntax for:
const private = new WeakMap();
class Test {
constructor() {
private.set(this, {
x: 0,
myMethod(value) {
private.get(this).x = value;
}
});
}
myPublicMethod() {
private.get(this).myMethod.call(this, 'test');
}
}
This will remove the collision issue and keep encapsulation.
Funny thing is, that's a solution as old as WeakMaps themselves are. Excuse the wayback machine link, but here is an example https://web.archive.org/web/20140209122326/http://bbenvie.com/articles/2012-07-25/JavaScript-Classes-with-private-protected-and-super
Should we say it "x"? "sharp x"? "hash x"? "private x"? How are we gonna communicate easily between us, human beings? Naming things is already hard. This proposal makes it even harder, because we have to think about accessibility at the same time as finding the correct name.
I put this link to Dijkstra point of view on identifiers if you are interested, which I think is aligned. https://www.cs.utexas.edu/users/EWD/transcriptions/EWD09xx/EWD958.html
TL;DR naming things is already not simple at all.
Private Fields and Methods are absolutely necessary I think, and I thank you guys for all your hard work in this and the private class fields proposal.
One problem with both solutions is, at least in my opinion, they make changing between public and private hard. I would happily change most class methods and fields to private, but changing every call and every reference is tedious.
I still do not follow the reasoning, why there is a need for a sigil at all. I mean I do understand the arguments, but don't think they are particularly convincing. I just re-read the FAQ @bakkot mentioned and it basically comes down to this:
Adding the prefix is the easy solution, while the right solution would be the Java-like Syntax everyone expects. This however is much dreaded, since property lookup is already complicated. Which might be a valid concern, but syntax matters a lot. Considering performance, I am quite sure, it is trivial for browser vendors optimize property lookup with runtime checks to be not noticeable. I assume accessing private fields will be faster than prototype properties, so fast adoption what something we want. Which is easier done with a nice syntax.
@bschaepper, given the constrains, the committee feels the sigil is the right solution. We would not have chosen to go forward with it otherwise. The penalty of overloading this.x
for property access isn't just in performance, but in complicating the mental model of property access even further: for example, this.x
currently always goes up the prototype, but private field access by design does not.
As to changing between public and private, that's something I'd expect tooling to handle pretty well, just as it currently handles renaming fields.
That might be true for novices, but not for anybody who knows other OOP languages. To me, property lookup is perfectly logical and simple. You can always do stupid and confusing things, but otherwise things are great since classes and arrow functions, even for beginners.
Why we have to reinvent the wheel here is beyond me. Same goes for the whole "hard vs. soft private", and whether we want the Java equivalent of protected or private, or at all. There is one sane was to do it, and that is how the other major OOP languages do it, period. Just look how everybody assumed it would be done, look at TypeScript.
Anyways, I am very much looking forward to real privacy in JavaScript, even if I have to use ugly, hard to type # chars ;-)
That might be true for novices, but not for anybody who knows other OOP languages.
I disagree, but also "this is confusing unless you also know a different language" doesn't seem that compelling to me.
There is one sane was to do it, and that is how the other major OOP languages do it, period.
Other major OOP languages have static type systems, as a rule. We have different constraints.
Just look how everybody assumed it would be done, look at TypeScript.
TypeScript's private fields aren't actually private, though.
As @bakkot and I have explained, these other syntax proposals just don't seem feasible, unfortunately.
Why not use this grammatical sugar: attributes or methods that begin with an underscore are privatized without the need to add the keywords "private" or "#". For example:
class Animal {
_type = "human" // private attribute;
age = 21; // public attribute;
constructor(type, age) {
this._type = type;
this.age = age;
}
// private method
_privateMethod() {
console.info("this is my private method");
}
// public method
toString() {
this._privateMethod();
return '(' + this._type + ', ' + this.age + ')';
}
// _type get set function
get Type() {
return _type;
}
set Type(type) {
_type = type;
}
}
let animal = new Animal();
animal.Type // yes
// _type cannot be accessed through this, age can;
animal._type // error: private attribute
animal.age // yes
// _privateMethod cannot be accessed through this, toString can;
animal._privateMethod() // error:
animal.toString() // yes
Don't you think it's more concise?
@Guxingzhe That was discussed before. Underscore has been used for a while to mean "this should be private, please don't touch it". But sadly we know this convention has been broken so many times, doing this modification to the language will mean tons of libraries and applications will break.
Remember: Don't break the web.
I'm not in favor of the current proposal but I understand there has been no better option yet.
@amatiasq Thank you for your answer, I only later thought of "undercode" and "loadash". It is acceptable to use "#" as "_";
The proposed syntax for private fields is absolutely disgusting, to simply put, it is confusing, is without prior art and very much alien to the elegant syntax JS has.
I must ask, why did you decide to use such an ugly syntax? Last I checked
private
had no use at all. Combine that with the fact that we already in the process of adapting metaproperties, here is my proposal to you as to what an elegant syntax would look like:Reference:
function.sent
meta propertynew.target
meta propertyAs much as I despise the idea of private fields, as I do believe this goes very much against the spirit of the open web and my love towards userscripts, at least make this abomination something pleasing to look at.