-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Ergonomics at price of semantic complexity #7
Comments
This suggestion sounds somewhat like Justin’s proposal from January which did not achieve consensus for stage 1. |
Thanks for the writeup! The only real downside in ergonomics I can see to this suggestion is that
Almost. My proposal was about changing access semantics (prototype lookup, can be installed on foreign objects without any fuss) as much as the eventual reification. Now that we've decided that branded-weakmap semantics are a requirement, we could just have a private symbol reification that acts like a branded-weakmap. Unfortunately, that doesn't simplify a whole lot with my private symbols proposal. Proxies will again have to update their internal methods to not call traps (though now they'd throw if not installed on the proxy instead of tunneling). Additionally, we'd still need the "known private symbols" API to be added to satisfy membranes. |
I hold no real opinions about the sketch I suggested, but I felt without proposing a way forward my post was just complaining about the current proposal. |
What if we leveraged the existence of Symbols as they are today, but added a new way of using them for assignment/access of private fields. Something like: export const GREETING = Symbol();
export class Hello {
#[GREETING] = 'Hello' // regular computed property access
#place = 'world' // regular private fields proposal
say() {
return `${this.#[GREETING]} ${this.#place}!`
}
} This would allow sharing of private fields across module boundaries through symbols as can be done today with non-private members. It wouldn't require use of a new keyword, and seems easily teachable as it only adds one new concept (dynamic private field accessor) that closely matches existing behaviour (dynamic property accessor). |
I wanted to voice my reservations around this syntax, to try to re-articulate what I was stating at TC39.
Let me put it out there first that I am definitely for some kind of private field access in both Classes and Object Literals. I think contrary to some of the commentary; having private fields in Object literals would be a welcome change.
Having said that I think this proposal points things in the wrong direction. It tries to borrow parts from two separate places (Class private fields, and Lexical Scope Semantics), but it changes the rules of these in significant ways which hurt the mental model of the language. I also don't think the pedagogical ramifications are worth the trade-off.
As I was saying to you after the March meeting, there is a trade-off between ergonomics and complexity of the mental model. By adding new syntax I hope we can simplify the mental model of the language. Case in point think private fields increases ergonomics and simplifies the mental model; because it reduces interaction and uncertainty (and therefore bounds checks) around a WeakMap. Users can forget about WeakMap, effectively dropping it from their mental model, and the additional complexity burden is simply remembering an additional
#
sigil. If private declarations come as a layer over private fields then they increase the complexity trade-off.The two "Alternative" sketches you proposed, I feel have fairly large issues:
Concerns with "Alternative 1" Sketch
This mirrors the semantics of lexical scoping, but comes at a cost - which is that the existing Stage 3 private fields proposal runs contrary to lexical scoping rules. It already comes with the implicit knowledge that
#place =
is scoped to the class. This proposal now adds additional layering to suggest that#place =
inside of a class could mean "private" or "shared private" - and in fact there is no way to ascertain this just looking inside of the class:While this is also true of variable bindings - there is an implied contract that the user simply needs to look up to find the nearest
const
,let
orvar
; this doesn't exist with private names.. If proposal advances based on this step, I can for-see a future where users will practice cargo cult programming and simply defensively always useprivate #name
inside classes, which will be a loss for the ergonomic wins of private fields.This is however a minor issue compared to alternative 2:
Concerns "Alternative 2" Sketch
This example runs contrary to lexical scoping semantics, because the
outer
keyword is doing the hole punching - so this pattern is the inverse of what we already have learned withlet
/const
/var
in that private names are implicitly scoped unless preceded with a keyword stating otherwise. While this makes classes require less context, it goes even further to complicate the mental model by requiring developers to learn a "new thing" which on the surface looks like lexical scoping but is almost the opposite. Not only are developers required to learn the "new thing" but they also have to switch contexts between private declarations and variable bindings. I believe this sketch will be far too mentally taxing and far too difficult to teach to be useful.A suggestion for a way forward
I humbly suggest it might be better for us to move away from borrowing from both lexical scoping and private fields. I think it might be better to move away entirely from one or the other. Might I suggest a pattern in which borrows from Symbols instead;
private foo
creates a private Symbol-like value which can be used with computed property access, like so:This suggestion does not run contrary to lexical scoping rules;
private foo
could be used anywhere thatconst foo = Symbol()
could be. Property access leans on already existing semantics, so there is nothing new for developers to learn there. The only additional learning is thatprivate foo
will create a Private Symbol (a Symbol that cannot be reflected upon). This proposal does not alter private fields in any way, and as such does increase the complexity of private fields.The text was updated successfully, but these errors were encountered: