-
Notifications
You must be signed in to change notification settings - Fork 113
Proposal: keyword to replace #
sigil
#56
Comments
In your example, |
I'll look at this a bit more soon, but a first note: |
Ah, yes, that was a rather silly oversight. In that case, it would probably need to be |
The goal of this proposal is true privacy, so exposing them programmatically like that is tough, which is why the goal is for it to be syntactic. Also important because if there are subclasses and they each have private properties with the same name, programmatic access has no way to distinguish them. |
To be honest, I'm still a bit unclear as to why class instances should be able to access each others' private fields at all. The |
Ah, interesting, thanks for the reminder/explanation @loganfsmyth. I'm curious what EDIT: thinking through a bit more, I assume this simply isn't possible to transpile with exactly correct semantics... |
Right now it'll likely be
It's generally the standard for
It's not guaranteed that all data being compared is public, or maybe the internal representation of the value is different from the public API, or it would allow for simpler comparison logic. Maybe there is internal state that isn't important to the user, but is important to the functioning of the class. |
Cool, thanks for the diff, that's helpful. I haven't used In any case, I assume The only alternative I can think of is a prefix unary class Point {
private x;
private y;
constructor(x = 0, y = 0) {
private x = +x;
private y = +y;
}
get x() { return private x }
set x(value) { private x = +value }
get y() { return private y }
set y(value) { private y = +value }
equals(p) { return private x === private p.x && y === private p.y }
toString() { return `Point<${ private x },${ private y }>` }
} I believe this could have similar precedence to I find this ugly, and probably surprising coming from other languages, but possibly less so than Thoughts? |
I think that's technically feasible, although it gets quite awkward for nested access (what does
Also, one more note: |
Hmm, I certainly agree the Frankly, though, In other words, I don't predict that Most javascript users will probably only interact with the feature when reading library code to debug something, and As language features go, I would guess that On those grounds, I am hopeful that free sigils would be preserved for features that might be more commonly-used, and that some awkwardness with a rather niche, advanced feature would be tolerated. Thoughts? |
With the rest of the syntax you've proposed, much. Especially to users of languages like C++ and Java, for whom "Surprising" is less about the very first time you use it and more about all the rest of the times.
Does it? I dunno; I think those are the people for whom the feature will be necessary, but I expect plenty of people will use it. Any time they don't want other code mucking around with their internal state, basically.
Mm... having bad syntax in the language is a cost even if most people rarely need it. "Powerusers would still use it" isn't sufficiently good justification for bad syntax. Personally, I also don't expect there to be all that many new syntactic features in the language in the future, beyond some of the current proposals, so I am less concerned about reserving syntax for future features. (OK, full disclosure, not just "don't expect", but "intend to prevent unless there's extremely good reason"; there simply isn't that much syntax a language can tolerate.) I think if you want the |
Hmm, interesting, thanks. Judging from a few threads (eg tc39/proposal-private-fields#14), I think there may be disagreement between the community and TC39 on whether I'm coming from a biased perspective of finding the notion of private fields to be an antipattern in general; I would much rather JavaScript not have them, but if it must, a little inconvenience doesn't bother me 😄. I would imagine that TC39 members feel differently; it seems they have fought hard, often against the community, for this feature. Feature design takes time; I won't be ready to propose something by the time this feature is adopted. Others in the future may have better feature ideas than either you or I can imagine today. In any case, I'll amend this issue's description to reflect the current state of the proposal, wait a few days to see if anyone else is interested in weighing in, and close it if there is no further support. |
Can anyone explain why PHP manages to do it with private keyword and JS can't ? |
@rattrayalex If you take a look at this discussion, you can see quite a bit of history and some extensively (exhaustively?) discussed proposals. I participated quite a bit, and somewhat vigorously agree with your distaste for the |
How about this?
or this syntax
|
@bakkot But the FAQ doesn't provide any proofs that adding additional logic on access to property make execution slowly. It was already noticed in other discussion #15 (comment) So, adding additional declaration for private field class Foo {
private x;
} we can mark this property as Also, JavaScript engines doesn't execute absolutely the same steps from specification. Therefore, without implementation details, we cannot talk about complexity and execution speed. |
@claytongulick @bakkot the rather slow coming-around seems like it may take rather a long time with the entire javascript community... I certainly see why special syntax is needed at the point of access, and why a mere I'm not clear on why a sigil is needed instead of a keyword for this access ( I also have to say, the |
I have updated the description to request the syntax I would invite @bokodi to open a separate issue suggesting |
(glancing through a few other issues, I just want to commend the maintainers for the amount of negativity they've put up with – eek! you have my sympathy) |
That's unfortunate, but it's the sort of thing we try not to let influence us too much. "The future is longer than the past" is the stock phrase here - that is, we try to care more about design that will be good for future programmers, rather than design that will make current programmers happy, since there are probably more future programmers than current programmers.
It's true that we could, in principle, have
That means something entirely different in C++, so is probably unacceptable on those grounds alone. But more generally, you still have to figure out what declaration would look like under that proposal - not class Foo {
name;
#secretId;
constructor() {
this.name = 'Bob';
this.#secretId = Math.random();
}
} Anyway, other syntax proposals have been discussed at some length already, including the Re: your second comment: please take a look through the existing issues before opening new ones; these suggestions have all been discussed before. |
Sorry @bakkot , I updated my proposal while you were typing to recommend something you might like a little better. Declare: Which I think is fairly clear / unambiguous – would you agree? It also makes property access look like property access, which I agree is a desirable property. I won't comment on Apologies for rehashing discussions that have been had; I've tried to scroll through several of the conversations. They can be lengthy and haven't always seemed so productive 😄 (again, you have my sympathy). |
Personally, no. I'd disagree pretty strongly with both, actually. As the first question in the FAQ says, I think And I don't think
Well, yes. Like I say, if you have suggestions for things I can add to the FAQ to better answer these sorts of questions before they get brought up again, I'd be very interested! |
It's my impression that the syntax above I have is workable; if that's incorrect, I think I'll go ahead and close this issue. If it's not unworkable (eg; clashes with existing syntax, or contains unresolvable ambiguities), I'd like to leave it open for a bit and then close if there's no appetite for this over (EDIT: whoops, posted before reading your most recent comment again). It seems this suggestion doesn't appeal to you, so I'll close it. Hopefully the great minds of the javascript community can come up with another alternative; I don't think anybody has claimed much fondness for |
Regarding the FAQ, I don't have any ideas; I think the feature as it stands is nuanced, and there does not exist a simple explanation of it. To me, that implies that we have an overcomplex feature on our hands, which might give a language designer pause. I'm sure the champions of this feature are considering the tradeoffs carefully. |
The FAQ is mostly intended to address the reasoning behind this choice of syntax and semantics, rather than to describe them. The reasons behind the current proposal are indeed pretty nuanced, but most people shouldn't need to know them, and I think the explanation of how the proposal works is actually quite brief: Use That's... pretty much it, modulo some details about proxies and evaluation order and so on, most of which apply to public fields too. |
Right, it's just that judging from existing threads, a lot of people are likely to ask "why" 😄 |
I agree with @rattrayalex that the syntax is unambiguous. If you would be happy writing things like this, then it would work just fine, in principle: class C {
private x;
private y;
constructor(x, y) {
private this.x = x;
private this.y = y;
}
print() { console.log(private this.x + private this.y) }
} Where I'm skeptical of @rattrayalex 's proposal is if this is something people would prefer to write most of the time, rather than the one-character sigil. The most common suggestion I've heard is to just use the same syntax as TypeScript, which omits the There is a particular hazard to @rattrayalex 's proposal, which is that if a programmer omits the class C {
private x;
private y;
constructor(x, y) {
this.x = x;
this.y = y;
}
print() { console.log(this.x + this.y) }
} The second version of the class would just work--pass all the tests, everything--with just the minor problem that |
Reopening because I think @littledan raises some interesting thoughts, and I'm curious for broader discussion. |
Yeah, I'd consider that a design flaw. Say you're publishing a public library where the expectation is that users will subclass some constructor.
and you publish that and users will be extending it. Say they have
so a year later you want to publish an update to
but what do you name it? If private properties could overlap and cause errors with other privates, or with public properties, there's no string/private key that you could choose without risking that you'd break one of your users. Your options would be to randomly generate a key name, or use a Symbol. Randomly generating a name wouldn't work with Private syntax, and Symbols aren't private, just guaranteed not to overlap. Having true privacy is a big part of what makes this proposal actively useful and safe to use. |
You make a valid point, but why can the same not be achieved for the
Maybe that's where I'm failing to understand this. Because so far it's been about public/private name collisions from what I understand. Which if it's using lexical scoping then the private shouldn't conflict with the public and inside of the class it should be referencing the private. Going forward if the language changes enough to implement public and private properties like other languages then there wouldn't be any refactoring necessary. That would seem more ideal. Not to mention semantics, |
@Knight-Yoshi so, again...
If I inherit from Foo, and have a public property "x" on the child class, what about that? What if the super class method now wants to access property "x"? Does it get the private variable from the super class, or the public variable from the descendant? Remember that in JavaScript, classes (objects) are basically dictionaries of properties and they are used in this manner. |
@Knight-Yoshi specifically, "private" means that it must be possible to not even observe the existence of a private field from outside the class. |
|
Thanks for the explanations @loganfsmyth , @bakkot and others. Seems like this line of inquiry has been thoroughly explored and we should leave the proposal as it currently is. |
What about: p[Symbol.private].x ? So, Then you can still declare variables with |
And, assigning |
@jwalton Symbols are observable by Proxies, through Edit: Those concerns won't apply in the explained case, i must have misunderstood it the first time around. There is an alternative proposal that uses the private keyword for both creation and access https://github.com/thysultan/proposal-private-methods-and-fields |
Yes, but obtaining the symbol isn't a problem; it's a well known symbol, you can easily get it from |
@thysultan nice, your proposal at https://github.com/thysultan/proposal-private-methods-and-fields looks great. Has it received any interest or support from TC39 folks? |
@rattrayalex wont work because "private" (the method described in that proposal) is a valid identifier and can collide with anything else named "private".
Also, what if something named "private" is defined in an outer scope? EDIT I've been corrected below, but ... I'm not entirely wrong as I'll explain below... |
@aikeru
|
@ljharb I'm sorry, you are correct. window["private"] = true
window.private // returns true
private // returns true ...but who in their right mind would do this? :) Right...? Right...? |
@ljharb some sort of semantic for |
@aikeru the last line throws a syntaxerror in strict mode (and the new |
The I don't believe any TC39 members have expressed interest in adopting it. |
Class code is always in strict mode so that should not pose a problem. |
Thanks @bakkot ! |
For the benefit of others, the summary I could see was a quote from @bakkot as follows:
along with this followup, also from @bakkot . Those don't seem like Hard Blockers in TC39 terms to me, although I agree they seem like downsides. Perhaps this approach warrants broader consideration? |
@rattrayalex, for completeness, there's also
As I say, I think these are collectively fatal to anything like this proposal. |
Ah, thanks for sharing.
Hmm. I'm not sure if the magnitude of confusion compares to the confusion
surrounding # (ie, "private" is self explanatory, even if the usage is a
bit idiosyncratic).
The other point, yeah to me sounds like an argument in favor of `private
this.bar` and `private that.baz` (so your example might be written
`private(obj.a)()`
I think that may have been rejected earlier on this thread, however.
In any case I think it would be disappointing if the committee did not
discuss syntactically viable alternatives in the face of such strong
community opposition to the standing proposal.
…On Mon, Apr 30, 2018, 09:14 Kevin Gibbons ***@***.***> wrote:
@rattrayalex <https://github.com/rattrayalex>, for completeness, there's
also
- the bit in the FAQ: having private x for declaration and anything
other than this.x for access seems likely to be extremely confusing
- confusion about the receiver for method invocations - I would expect
private(a).x() to have private(a) as its this, not a, which is
extremely awkward.
As I say, I think these are collectively fatal to anything like this
proposal.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#56 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAq_Lo4d3QW7hp_UYkwSslpW-qFLEsfSks5ttzhQgaJpZM4QSmeJ>
.
|
I'm not sure what this means. We have discussed them. At very, very great length, both on github and in committee. The result of those discussions was that we generally felt those alternatives were too flawed to go forward with. |
Having TBH, I'm starting to think the "private variables in Javascript" is the part that's fatally flawed. Does anyone know of another prototype based language with private variables? |
@bakkot There are numerous flaws that affect the The flaws mentioned against |
@bakkot apologies – that didn't come out well 😅 you guys have been unbelievably open and patient with the community, and your willingness to hear uninformed ideas such as my own has been humbling. I meant specifically about "use You personally have taken the time to think that one through, and have found a few problems with it (thanks!) but I would be curious for a broader set of eyes. That said, we're all a bit tired of this proposal at this point and are probably going home to our two camps of "just merge it" and "just drop it"... new solutions to try to appease the crowds aren't likely to have much progress. Good luck 🙂 |
... I just foresee a lot of confused misuse of |
(I have edited this description from the original in response to feedback; original is here)
In https://github.com/tc39/proposal-private-fields, I see a redirect to this repo for future discussion and current status, as well as this:
There seems to be general dissatisfaction with the
#
sigil for private fields. I would like to propose an alternate syntax with the same semantics:Use a
private
unary prefix keyword to access a "private this", such thatprivate this.foo
is identical to the currently proposed#foo
.Other possibilities for the keyword include:
Advantages:
private
is already reserved, and would have no other reasonable use.#
is the only "free sigil" left on a US keyboard for JavaScript (that I know of) and might be better saved for a feature which would be used in both application and library code, rather than only library code.private.
is for;#
is not likely to be immediately clear.It is more obvious thatprivate this.x
andthis.x
are completely separate, and can peacefully coexist as unrelated fields.this.#x
andthis['#x']
.Downsides:
private this.foo
would likely be surprising to a Java or C# engineer, whereprivate
is used differently. (I would argue this is similar to the existingself
/this
differences).private
is already implemented in TypeScript, and this would clash. (I would argue TypeScript would likely be able to adapt).(original proposal was
private.foo
instead ofprivate this.foo
)The text was updated successfully, but these errors were encountered: