Closed rattrayalex closed 6 years ago
In your example, p.private.x
would conflict with a public property named "private" on p
, so that's a non-starter.
I'll look at this a bit more soon, but a first note: p.private.x
is already legal syntax, and I don't think we want to change its meaning.
Ah, yes, that was a rather silly oversight.
In that case, it would probably need to be Object.getPrivateField(p, 'x')
or similar, but I'm not sure that approach would work either.
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 equals
method in the Point
seems like something that should read from a publicly-accessible getter on the "other". I assume I'm missing something, though.
Ah, interesting, thanks for the reminder/explanation @loganfsmyth. I'm curious what p.#x
would compile to in a Babel scenario; is there an example of that anywhere? (I haven't spent as long on this proposal as I like to).
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 WeakMap
values https://github.com/babel/babel/pull/6120/files#diff-1c2c94ad021e392a33a5501ebf552d1aR6
I'm still a bit unclear as to why class instances should be able to access each others' private fields at all.
It's generally the standard for private
. https://github.com/tc39/proposal-private-fields/issues/90#issuecomment-307201358
The equals method in the Point seems like something that should read from a publicly-accessible getter on the "other".
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 private
in other languages.
In any case, I assume p.private.foo
is unresolvable, and it sounds like that feature is a hard requirement.
The only alternative I can think of is a prefix unary private
keyword for access:
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 typeof
.
I find this ugly, and probably surprising coming from other languages, but possibly less so than #
(obviously very subjective).
Thoughts?
private p.x
I think that's technically feasible, although it gets quite awkward for nested access (what does private foo.bar.baz
mean? is bar
the private field, or baz
, or indeed is foo
a private field of this
?) but I certainly find it more awkward and surprising than #
.
#
has a nice story, which is that it's part of the name of the field: where we might previously have written obj._foo
to mean that _foo
is intended to be private, now we can write obj.#foo
to mean that #foo
is actually private.
Also, one more note: private
is legal as an identifier name in sloppy-mode code, which makes it a bit weird to give it keyword semantics in class bodies. It's viable, since class bodies are necessarily strict, just... weird.
Hmm, private foo
is more surprising than #foo
?
I certainly agree the private other.foo
is awkward, and parens may be needed in certain cases to distinguish (users may choose private(other.foo).bar
as syntax).
Frankly, though, private
seems like a feature that will be primarily written by a fairly small number of advanced javascript users (library authors) in a fairly small set of circumstances (class instance fields that must not be exposed). Indeed, I would expect these authors to be comfortable with the semantics of typeof
, for example, and reading MDN docs in general.
In other words, I don't predict that private other.foo
would be sufficiently confusing or awkward to unduly inhibit its use from the target audience as I understand it.
Most javascript users will probably only interact with the feature when reading library code to debug something, and private foo
is more likely to be loosely intuitable than #foo
.
As language features go, I would guess that private other.foo
/other#foo
is likely to be about as common as bitwise shifts or xors, which many JavaScript users (including some advanced users) are not aware exist at all.
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?
Hmm,
private foo
is more surprising than#foo
?
With the rest of the syntax you've proposed, much. Especially to users of languages like C++ and Java, for whom private foo
as a declaration is very strongly tied to this.foo
as access, which, as the FAQ points out, will not error but will just silently have the wrong semantics. (I don't think private.foo
is enough to avoid that either.)
"Surprising" is less about the very first time you use it and more about all the rest of the times.
Frankly, though,
private
seems like a feature that will be primarily written by a fairly small number of advanced javascript users (library authors) in a fairly small set of circumstances (class instance fields that must not be exposed).
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.
In other words, I don't predict that
private other.foo
would be sufficiently confusing or awkward to unduly inhibit its use from the target audience as I understand it.
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 #
to be used for something else, you'd be better served by arguing for that feature, and why that feature is as necessary and as dependent on a sigil as this one. And keep in mind that the likely outcome of successfully convincing the committee to deny #
to private fields would probably be "the language has no private fields", not "private fields go in with awkward and surprising syntax"; that would be the burden to overcome.
Hmm, interesting, thanks.
Judging from a few threads (eg https://github.com/tc39/proposal-private-fields/issues/14), I think there may be disagreement between the community and TC39 on whether #foo
is "good syntax".
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 #
syntax. I have to say though, due to the patience and excellent technical points of @bakkot and @littledan I've started to come around. Maybe spend a little time reading through that discussion and see if you come out of the other side of it with the same opinion? I'd really prefer that we separate privates from the class field proposal to wait until we get consensus and a more generic approach to access modifiers overall, but like I said, as I've spend more time dwelling on it, I'm starting to really see why #
is the only feasible way to deal with privates. To @bakkot and @littledan 's point as well - I'm authoring a framework and app designer based around drag and drop web components, and I'm really wishing for a hard private sigil of some kind. this._please_dont_change_me
isn't cutting it.
How about this?
class Point {
private x;
private y;
constructor(x = 0, y = 0) {
this..x = x;
this.['y'] = y;
}
equals(p) {
return this..x === p..x && this..y === p..y;
}
toString() {
return `Point<${ this..x },${ this..y }>`
}
}
or this syntax
class Point {
private x;
private y;
constructor(x = 0, y = 0) {
this->x = x;
this->['y'] = y;
}
equals(p) {
return this->x === p->x && this->y === p->y;
}
toString() {
return `Point<${ this->x },${ this->y }>`
}
}
@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 https://github.com/tc39/proposal-class-fields/issues/15#issuecomment-317155488
So, adding additional declaration for private field
class Foo {
private x;
}
we can mark this property as private
and check this flag at property access.
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 private foo
declaration alone is not enough.
I'm not clear on why a sigil is needed instead of a keyword for this access (typeof
seems like fine precedent here).
I also have to say, the this->myPrivateField
syntax seems much nicer to me than #myprivateField
... I haven't given a thorough read, though, so perhaps that would be unworkable.
I have updated the description to request the syntax private this.field
and private other.field
, which I believe does not clash.
I would invite @bokodi to open a separate issue suggesting ->
syntax.
(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)
@rattrayalex
the rather slow coming-around seems like it may take rather a long time with the entire javascript community
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.
I'm not clear on why a sigil is needed instead of a keyword for this access
It's true that we could, in principle, have private [no LineTerminator here] IdentifierName
mean this.#x
. But there's a few problems with that - first, what would accessing that.#x
look like; second, what would declaration look like? No answer to these has yet seemed adequate, nor does a novel one seem likely to. (And from a more stylistically perspective, it would be a shame if property access did not look like property access. private x
just doesn't look like property access to me.)
I also have to say, the
this->myPrivateField
syntax seems much nicer to me than#myprivateField
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 private x
, presumably. So some other new syntax? I have to say I don't entirely understand the perspective which finds that to be nicer than
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 ->
one and the one with a keyword for access. I don't know that I can address all of them in the FAQ, but certainly if you have suggestions for other things to add to the FAQ I'd be glad to hear them. In the mean time, I'm just going to have to point you to the existing lengthy discussions.
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: private x;
Access on this: private this.x
Access on that: private that.x
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 ->
since that belongs in a separate thread, though I hope it's not snide to mention that #foo
means very different things in other languages, from macros/pragmas to comments (I believe its meaning in JS would be fairly novel).
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).
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.
Personally, no. I'd disagree pretty strongly with both, actually.
As the first question in the FAQ says, I think private x
as a declaration where access is anything other than this.x
/ that.x
is a no-go.
And I don't think private this.x
looks like property access. Or rather, it looks like referring to the public field x
and applying an operator to it, just as typeof this.x
does. (This is especially problematic with nested property access, as I mentioned upthread when you proposed it earlier.)
They can be lengthy and haven't always seemed so productive
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 #x
in a class body to declare a private field and obj.#x
to access it (where previously you might have written _x
and obj._x
and just hoped your users would respect that); privacy is enforced by restricting the ability to refer to #x
to the body of the class declaring it (that is, by lexical scope, the same way it is enforced for closures); private fields cannot be accessed dynamically; attempting to access a private field on an object which lacks it will throw a TypeError.
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 private
on uses.
There is a particular hazard to @rattrayalex 's proposal, which is that if a programmer omits the private
keyword in the class body aside from declarations, using instead the TypeScript syntax, then everything just becomes public. To take the above example,
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 x
and y
are ordinary public properties. I think this hazard is particularly severe because it matches exactly how some other systems currently denote private, but without any privacy at all.
Reopening because I think @littledan raises some interesting thoughts, and I'm curious for broader discussion.
The hazard you raise seems particularly scary.
Any linter would likely add a recommended rule to protect against this; when private x;
is declared, accessing this.x
without private
should probably raise a linter error.
Come to think of it, I'm not sure that this footgun is absent from the status quo proposal:
class Foo {
#x;
bar() {
this.x = 3; // oops!
}
}
While I certainly agree it looks worse in the proposal I have made, even with #
the above could easily occur if the author did not fully understand the #
feature (eg; a quick glance at the docs could lead to somebody writing code like this), or because they simply missed a #
when scanning a large block of code (ie; this.somePrivateField
and this.#somePrivateField
are visually similar).
As such, #
should probably be used with a lint rule similar to the one I described above.
(Such a linter rule would need to handle cases where both private x
and x
are declared).
Another approach might be to discourage declaration with private
, or even disallow declaration without an initial value:
class Foo1 {
private x;
constructor() {
// Surprising that you need `private` here.
private this.x = 4;
}
}
class Foo2 {
constructor() {
// Arguably this is less surprising with the declaration omitted.
private this.x = 4;
}
}
class Foo3 {
private x = 4;
constructor() {
// At least this would obviously fail while developing if you omitted the `private`.
const y = private this.x * 2;
}
}
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.
That's certainly a valid critique as well; the syntax I am proposing would be unarguably less ergonomic for authors.
I view this as a feature, not a bug; use of private
fields should be discouraged amongst most application developers. As far as I understand it, this language feature is intended primarily for library authors who Know What They're Doing and have Read The Manual.
Furthermore, even experienced library authors are imposing a cost on their users every time they use private
, because it hinders debuggability. This tradeoff is probably worthwhile in certain cases, but as the status-quo proposal stands, it will be more convenient to declare/use private fields than public ones: #foo
vs this.foo
.
This could encourage private fields as the default among application and library authors alike, which may harm the debuggability of the JavaScript ecosystem as fields which are safe to expose become locked-down.
hmm, this gives me another idea...
One minor quibble:
The second version of the class would just work--pass all the tests, everything
I would hope that if indeed the privacy of the field were important, the author would have written a test for its privacy.
I would also add that this is not a very harmful error case; the code still works as expected.
A far more dangerous failure mode would be one like this:
class Foo {
#somePrivateField = 7;
increment() {
return this.somePrivateField = this.#somePrivateField + 1; // Spot the typo!
}
}
where the code does not work at all (and, in this rather contrived case, the private value is exposed to boot).
This class of bug seems more likely in a world with #
than private
because it's easy to miss a single character. The class you mention is one where the author probably either gets it all right or gets it all wrong, which I would argue is less problematic.
Either way, this feature is dangerous to use without a linter.
Debuggability is unafffected, because actual debuggers will be able to show private fields. Absolutely the goal is to convince EVERY developer to make anything that can be private, private - not just library authors. More privacy is a good thing, always.
Debuggability is unafffected, because actual debuggers will be able to show private fields.
Surely they will; however, many programmers use tools like console.log(someInstance.someField)
for debugging. I know that some look down upon this form of debugging, but:
console.log
debugging is a widespread practice.Thus while debuggability is certainly not reduced to zero, it is affected.
The same might be said of testability. Certainly well-written software that makes use of private fields is, if anything, more testable than code without private fields, but poorly-written software may be much less testable when private fields are used everywhere. Unfortunately, a large percentage of software is poorly-written (I assume @ljharb would agree with this).
More privacy is a good thing, always.
Hmm, is this a universally-held opinion amongst language designers, library authors, and other software engineers?
@littledan
I agree with @rattrayalex that the syntax is unambiguous.
The ambiguity I meant to refer to was in private this.x.y
. It could be made unambiguous by picking one interpretation or the other, but I'd worry.
@rattrayalex
it will be more convenient to declare/use private fields than public ones:
#foo
vsthis.foo
.
I'm not sure I understand this. The shorthand isn't in the proposal anymore, if that's what you mean, so declaration and use for private fields is exactly like that for public fields, except that private fields are prefixed with #
(and can't be accessed dynamically). This symmetry is a pretty attractive part of the proposal as it stands, to me.
I would hope that if indeed the privacy of the field were important, the author would have written a test for its privacy.
I don't share this intuition. Certainly I am not in the habit of testing for the privacy of my private fields in my C++ classes, for example. (Also, I'm not sure how you'd go about testing it.)
I would also add that this is not a very harmful error case; the code still works as expected.
Strongly disagree. The code has the semantics you expect except that more things are part of your public API than you intended. That's a much subtler problem to notice, and a harder one to fix once it goes out in the world.
This class of bug seems more likely in a world with
#
thanprivate
because it's easy to miss a single character.
This is the sort of thing which is hard to discuss without some observation, unfortunately. For what it's worth, I don't share this intuition either, especially if you start treating the #
as part of the name, as the current declaration syntax encourages. And "mistyping field names" is a problem people are already accustomed to, as opposed to "omitting a contextual keyword which modifies property access".
Either way, this feature is dangerous to use without a linter.
Hm. It doesn't feel any more dangerous than public fields - i.e., if you mistype a field name, you get the wrong thing, which is indeed a serious danger but already irrevocably part of the language; is there some other danger you mean?
The shorthand isn't in the proposal anymore, if that's what you mean
Yes, that's what I meant; I wasn't sure if the shorthand had been removed. Thanks for clarifying; I rescind those comments.
Regarding writing a test for privacy, that's fair. I think you could write it like this:
it('does not allow public access to foo', () => {
const p = new Point(1, 2);
expect(p.x).not.toExist();
})
but I probably wouldn't write such tests myself either.
I would predict that this.foo
/this.#foo
typos will be common, but that's just a prediction. I agree that some observation would be needed to assess the danger of such typos, and I suggest that some such observation take place before making this feature an official part of JavaScript (eg; querying github usage).
j#, or #whatever
the situation
use # for private member
we don't like it
the thought
more than one thing under one name
prefix # to 2nd name, how about 3rd?
the proposal
prefix #1, not #, to 2nd name, i.e. this.#1x
the family
#v6js2017; // analog "use strict"
// your js2017 code here
#5f; // @f
#"111"#; // `111`
#3"111"; // `111`, copied from c++
the alternative
\ commonly used as another escape
😄
what about other access modifiers ? are we going to use different symbol for each modifier or are we restricting any other access modifier at all ?
@nika-begiashvili Other access modifiers could be provided by decorators, as outlined in this sample code implementing several access modifiers.
@littledan Why speed access is matter for private modifiers, but for protected is not? Instead, private and protected modifiers can be checked at runtime without any sigil prefixes (as I mentioned before https://github.com/tc39/proposal-class-fields/issues/56#issuecomment-347692690)
Pardon me, but I write JavaScript for a living and I don't find this.#foo
disagreeable. I would be very sad to discover I needed to type all of private this.foo
or similar to access private fields in JS, which don't behave the same as "private" in other languages and thus, shouldn't be assumed so.
If anyone is worried about typos with this.#x
it only seems that much worse with private this.x
as there are more cases in which more severe problems could be caused.
As an aside... It seems like everywhere I've seen that there are people who adamantly want a "private" keyword (as well as protected, readonly, abstract...) coincidentally tend to come from TypeScript, where private isn't really private in any sense, but the IDE helps make sure you treat it that way at design time. These type-system-related concepts do not translate well to a dynamic runtime where new code and conflicting definitions can be loaded on the fly, at any time, and you can't ensure that the "Foo" class defined in one context/window/etc. is the same "Foo" referred to in another. Transpilers like TypeScript have the huge benefit of...
JavaScript has neither of these guarantees/benefits, which is why it's not as simple as introducing a keyword, as much as that might be a desirable thing other languages can do. If it were easy, big corporations with genius talent wouldn't have been working on this since (at least) 1998 -- which they have been, on and off, at different times, including Microsoft, Adobe, Google, Netscape, etc.
This isn't the first time private
was proposed/requested for JS. That happened like, 20 years ago.
Apologies for the length.
If anyone is worried about typos with this.#x
I think people worry about introduction new awkward syntax (like php's $
) and about only private modifier support (yes, I read that protected
modifier should be support via decorators, but I don't understand why). Programming language is created for people, not for machines. From this point of view private
keyword is much more readable than some sigil before variable name. Of course, I suggest to write private
modifier only once at declaration and check later in access at runtime.
Current proposal for private fields looks like satisfaction of JavaScript parser.
Unfortunately, all my questions (e.g. https://github.com/tc39/proposal-class-fields/issues/56#issuecomment-351120108) are ignored by @littledan.
Edit: This is also introduce inconsistency in language, because module public entities are exported using export
keyword, but for class private members #
is used. For example, in Dart all identifiers started with an underscore _
are private in library.
@ikokostya I don't think your assertion that your questions are being ignored is at all fair. Your question has been answered more than once in multiple places. Perhaps you are not looking as hard as you could.
While it may be popular to say private is more readable, it's still subjective (ie: I say it's actually less so, because #
variables are lexically bound, and not this
bound), but we can put that aside for a second.
Your point about programming languages being created for people / not machines is a valid principle. Unfortunately, at the end of the day, a programming language whose meaning is in any way ambiguous to a machine or cannot be properly understood by a machine, is not a useful programming language. So, unfortunately, we're limited by what we can add to every existing JavaScript parser out there without making things too complex or breaking any legacy code, as well as targetting an entirely dynamic environment. Put simply, new syntax must play ball with parsing as it already exists today. Doing otherwise will break the web, which we cannot do and there is precedent for this.
I do not understand at all how or why you say that this introduces inconsistency with respect to the export
keyword, except that I can tell you that the import/export keywords have very strict limitations placed on them in order to work as they do. For example, you cannot dynamically at runtime create new exports or imports using the keywords, ie: you can't eval("export default foo")
. It's apples and oranges.
Dart, like TypeScript, again, gets to break from JavaScript. Dart doesn't need to follow the syntax rules or legacy constraints JavaScript is subject to, so it's rather irrelevant what it does compared to what JavaScript may be able to do because it has the same benefits JavaScript does not have.
You can disagree on the principles of not breaking the web or staying compatible or requiring all new JavaScript modules written with the syntax you want to be precompiled ahead of shipping to the browser, but these aren't likely to be productive because it's been tried before multiple times. You may just not be aware of attempts like StrongScript/SoundScript from Google or JScript.NET from Microsoft, for example. That these essentially do not exist today / were dropped should tell you something.
The TC39 github discussions in my experience have been nothing but open, taking all comers of any experience level.
While it may be popular to say private is more readable, it's still subjective (ie: I say it's actually less so, because # variables are lexically bound, and not this bound), but we can put that aside for a second.
I don't see why a property defined with the private keyword couldn't be lexically bound instead of using the octothorp.
I saw a statement that people currently use underscore to denote when something is private, thus that is one reason why the ocothorp was chosen. However, the underscore is notation for readability. Even in PHP when defining private properties I've seen the underscore be used private $_prop1
. It's just notation, not a language construct. If you don't use the private keyword for what its intended purpose, creating private members of an object, then what's the point of having it reserved. It'll never be used.
@Knight-Yoshi this has been answered already ... but I think it can be summed up to this...
//within a class...
constructor() {
this.privateVar = 5 //Does this refer to a real private variable, or a public one?
}
You should not be able to redeclare a property. In PHP this is valid
<?php
class Test {
private $name = 'Me First';
public function __construct() {
$this->name = 'Me Second'; // refers to the private $name variable
}
public function name() {
return $this->name;
}
}
$t = new Test;
echo $t->name();
Inside the class name references the private variable.
@Knight-Yoshi you can't compare php and JavaScript. They aren't bound by the same rules. What would you expect the behavior of this to be?
class Foo {
private bar = 5
constructor() { /* ... */ }
doWork() { console.log(this.bar) }
}
var f = new Foo()
f.bar = 7
f.doWork()
I would expect an exception/fatal error be thrown for trying to access a private property.
@Knight-Yoshi that doesn't work, because one of the explicit goals of the proposal is that private variables are undetectable from outside of the object. By wrapping a try/catch around that, I can detect that the private variable foo exists. Aside that, I'm also guessing that would also lead to a lot of surprising/undesirable behavior.
#bar
is necessary because it is literally impossible to collide with a public var / undetectable, because it is otherwise an invalid identifier.
(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.private 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
)