Skip to content
This repository has been archived by the owner on Jan 25, 2022. It is now read-only.

Proposal: keyword to replace # sigil #56

Closed
rattrayalex opened this issue Nov 6, 2017 · 82 comments
Closed

Proposal: keyword to replace # sigil #56

rattrayalex opened this issue Nov 6, 2017 · 82 comments

Comments

@rattrayalex
Copy link

rattrayalex commented Nov 6, 2017

(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:

Q: Can we reconsider, in the syntax, the decision to do...
A: Yes, it's not too late.

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 that private this.foo is identical to the currently proposed #foo.

class Point {
  
    private x;
    private y;

    constructor(x = 0, y = 0) {
        private this.x = +x;
        private this.y = +y;
    }

    get x() { return private this.x }
    set x(value) { private this.x = +value }

    get y() { return private this.y }
    set y(value) { private this.y = +value }

    equals(p) { return private this.x === private p.x && y === private p.y }

    toString() { return `Point<${ private this.x },${ private this.y }>` }

}

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.
  • It is immediately clear what private. is for; # is not likely to be immediately clear.
  • It would be friendlier to existing language tooling and implementations (eg; syntax highlighters, static analysis tools, and parsers would require minimal/no modification).
  • It is more obvious that private this.x and this.x are completely separate, and can peacefully coexist as unrelated fields.
  • It resolves the surprising difference between this.#x and this['#x'].

Downsides:

  • private this.foo would likely be surprising to a Java or C# engineer, where private is used differently. (I would argue this is similar to the existing self/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 of private this.foo)

@ljharb
Copy link
Member

ljharb commented Nov 6, 2017

In your example, p.private.x would conflict with a public property named "private" on p, so that's a non-starter.

@bakkot
Copy link
Contributor

bakkot commented Nov 6, 2017

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.

@rattrayalex
Copy link
Author

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.

@loganfsmyth
Copy link

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.

@rattrayalex
Copy link
Author

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.

@rattrayalex
Copy link
Author

rattrayalex commented Nov 6, 2017

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...

@loganfsmyth
Copy link

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. tc39/proposal-private-fields#90 (comment)

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.

@rattrayalex
Copy link
Author

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?

@bakkot
Copy link
Contributor

bakkot commented Nov 6, 2017

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.

@rattrayalex
Copy link
Author

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?

@bakkot
Copy link
Contributor

bakkot commented Nov 8, 2017

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.

@rattrayalex
Copy link
Author

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 #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.

@nika-begiashvili
Copy link

Can anyone explain why PHP manages to do it with private keyword and JS can't ?

@claytongulick
Copy link

@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.

@bokodi
Copy link

bokodi commented Nov 16, 2017

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
Copy link
Contributor

bakkot commented Nov 16, 2017

@bokodi, please see the FAQ.

@ikokostya
Copy link

ikokostya commented Nov 28, 2017

@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 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.

@rattrayalex
Copy link
Author

@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.

@rattrayalex
Copy link
Author

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.

@rattrayalex
Copy link
Author

(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)

@bakkot
Copy link
Contributor

bakkot commented Dec 9, 2017

@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.

@rattrayalex
Copy link
Author

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).

@bakkot
Copy link
Contributor

bakkot commented Dec 10, 2017

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!

@rattrayalex
Copy link
Author

rattrayalex commented Dec 10, 2017

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 #.

@rattrayalex
Copy link
Author

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.

@bakkot
Copy link
Contributor

bakkot commented Dec 10, 2017

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.

@rattrayalex
Copy link
Author

Right, it's just that judging from existing threads, a lot of people are likely to ask "why" 😄

@littledan
Copy link
Member

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.

@rattrayalex
Copy link
Author

rattrayalex commented Dec 10, 2017

Reopening because I think @littledan raises some interesting thoughts, and I'm curious for broader discussion.

@loganfsmyth
Copy link

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.

export default class LibraryBase {
}

and you publish that and users will be extending it. Say they have

import LibraryBase from "...";
class UserLibrary extends LibraryBase {
  #prop = 4;
}

so a year later you want to publish an update to LibraryBase that requires new instance-level data to be stored? The obvious thing would be to add a private

export default class LibraryBase {
  #prop = whatever;
}

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.

@KnightYoshi
Copy link

You make a valid point, but why can the same not be achieved for the private keyword, then?
It's just about what denotes the private property, yeah. So why can something that is more semantic for what it's suppose to do not be used? If they're truly isolated within their class as you're describing, then child doesn't know about it then there wouldn't be any parent/child naming conflicts. What is actually preventing something like this from working:

export default class LibraryBase {
}
import LibraryBase from "...";
class UserLibrary extends LibraryBase {
  private prop = 4;
}
export default class LibraryBase {
  private prop = whatever;
}

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, private is intuitive for what it represents. When I saw the octothorp from this proposal my first thought was, "what is this suppose to be?"

@aikeru
Copy link

aikeru commented Jan 15, 2018

@Knight-Yoshi so, again...

class Foo {
  private x = 5
  doWork() { console.log(this.x) }
}
var f = new Foo()
f.x = 7 //What does this do?
f.doWork() //What will this output?

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.

@ljharb
Copy link
Member

ljharb commented Jan 15, 2018

@Knight-Yoshi specifically, "private" means that it must be possible to not even observe the existence of a private field from outside the class.

@loganfsmyth
Copy link

this.prop in JS is already clearly defined as accessing a real object property. In the spec this means walking the prototype chain, potentially triggering Proxy handlers and so on. Trying to overload that to also have private access would complicate things hugely. It encourages developers to use incorrect mental models how privates behave. They essentially aren't traditional properties and thinking of them that way will cause developers problems. To me, differentiating private access as foo.#prop is a huge increase in clarity because it makes it dramatically easier to know where in your code you're relying on generic property access vs privates. And if we accept that as an ideal behavior, then having the class-level declaration be private x while the accessor is this.#x is just unnecessary differentiation when using the same symbol in both cases links them more clearly.

@littledan
Copy link
Member

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.

@jwalton
Copy link

jwalton commented Apr 20, 2018

In your example, p.private.x would conflict with a public property named "private" on p, so that's a non-starter.

What about:

    p[Symbol.private].x

?

So, Symbol.private is a new "well known symbol". Accessing x[Symbol.private] returns an object full of delicious private variables if you are allowed to access x's private members, and returns undefined otherwise.

Then you can still declare variables with private x, and you can access them with private this.x, and in the case where you're accessing someone else's private members you can use the magic private symbol?

@jwalton
Copy link

jwalton commented Apr 20, 2018

And, assigning someoneElse[Symbol.private] would throw an exception?

@thysultan
Copy link

thysultan commented Apr 20, 2018

@jwalton Symbols are observable by Proxies, through getOwnPropertySymbols and through monkey patching Symbol.private. Here is a thread that discusses more about private Symbols and the issues involved – https://esdiscuss.org/topic/ecmascript-proposal-private-methods-and-fields-proposals

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

@jwalton
Copy link

jwalton commented Apr 20, 2018

Yes, but obtaining the symbol isn't a problem; it's a well known symbol, you can easily get it from Symbol.private, or you can obtain it from getOwnPropertySymbols(). But getting the symbol doesn't get you anything, because evaluating somoneElse[Symbol.private] returns undefined. Object[Symbol.private] is a property that returns a different value depending on who is evaluating it.

@rattrayalex
Copy link
Author

@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?

@aikeru
Copy link

aikeru commented Apr 30, 2018

@rattrayalex wont work because "private" (the method described in that proposal) is a valid identifier and can collide with anything else named "private".
IE: what does this do?

private = undefined; //Assign "private" to undefined

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...

@ljharb
Copy link
Member

ljharb commented Apr 30, 2018

@aikeru private is a reserved keyword, so that's not entirely accurate.

private(obj) isn't necessary to achieve the very vaguely defined use case in that proposal - if you need dynamic lookup, store an object or an array or a Map in a hardcoded, static, private field.

@aikeru
Copy link

aikeru commented Apr 30, 2018

@ljharb I'm sorry, you are correct.
That said, this works just fine in Chrome today in the dev console:

window["private"] = true
window.private // returns true
private // returns true

...but who in their right mind would do this? :) Right...? Right...?

@rattrayalex
Copy link
Author

@ljharb some sort of semantic for private(this).foo === private(obj).foo is desired, no? My impression is private.foo is simply shorthand for private(this).foo, which seems convenient if unnecessary.

@rattrayalex
Copy link
Author

@aikeru the last line throws a syntaxerror in strict mode (and the new private feature could be reserved to strict mode only).

@bakkot
Copy link
Contributor

bakkot commented Apr 30, 2018

The private(obj) syntax has been discussed many times; I suppose it deserves its own entry in the FAQ, though I'm not sure I'm up to writing it. (It is partially covered by this question, I suppose.) If you open this issue, expand all the "hidden items", and C-f private( you should see a few of the previous discussions.

I don't believe any TC39 members have expressed interest in adopting it.

@thysultan
Copy link

thysultan commented Apr 30, 2018

@aikeru Related thread

Class code is always in strict mode so that should not pose a problem.

@rattrayalex
Copy link
Author

Thanks @bakkot !

@rattrayalex
Copy link
Author

rattrayalex commented Apr 30, 2018

For the benefit of others, the summary I could see was a quote from @bakkot as follows:

Again, though, I think that both of

  1. having private.x refer to a private field of this when inside of a class, and a public property of the variable private when outside, and
  2. having to write private(private(obj).left).right instead of obj.#left.#right

would be fatal to anything like this proposal.

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?

@bakkot
Copy link
Contributor

bakkot commented Apr 30, 2018

@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.

@rattrayalex
Copy link
Author

rattrayalex commented Apr 30, 2018 via email

@bakkot
Copy link
Contributor

bakkot commented Apr 30, 2018

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.

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.

@jwalton
Copy link

jwalton commented Apr 30, 2018

As I say, I think these are collectively fatal to anything like this proposal.

Having x.#foo and x['#foo'] return different values, as this proposal does, it at least as weird as your private(a).foo() receiver example.

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?

@thysultan
Copy link

@bakkot There are numerous flaws that affect the dot.#sigil syntax one of which is ironically the argument used against private.access, that is that it confusingly overloads the this.dot namespace.

The flaws mentioned against private.access stem around the argument that it would cause confusion, an argument that is either negligible in practice or can be equally applied to the dot.#sigil access syntax and based on community backlash would cause more than just confusion.

@rattrayalex
Copy link
Author

@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 private for access" – most discussion I could find was about using private for declaration only, which is an obvious no-go given the semantic requirements.

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 🙂

@rattrayalex
Copy link
Author

... I just foresee a lot of confused misuse of this.#foo... people using it everywhere when they don't need to and then getting confused when this.foo doesn't work, etc. I really hope there is some serious user testing with inexperienced JS developers before landing this as-is.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests