Hacker News new | past | comments | ask | show | jobs | submit login

Why can't the public/private distinction, if denoted with a "private" keyword instead of a # be preserved and enforced at runtime? The difference between `private count` and `#count` is purely syntactical.



Because the difference between `object.count` and `object.#count` is NOT purely syntactical. Information is needed at the call site to determine if it is a private field access compared to an object property access. This is because a private field, as defined in the spec, must not interfere with object properties.


> Information is needed at the call site to determine if it is a private field access compared to an object property access.

Is there? The object.#foo syntax tells you it is private, sure… but you still need know if access is permitted or not. For that, you need to look at some information on object and make a decision, but that information could also inform you as to whether or not the access is to a private field at all. Consider for object.foo, the following:

  1. look up, internally in the interpreter, the class definition (recorded when parsing the class {} block)
  2. Is .foo private? If no, behave "normally"
  3. If yes, decide if access should be allowed.
What about that doesn't work? If that does work, then, the # is pure syntax.

One thing I'm curious about, since you seem adamant that this isn't syntax (particularly since the docs raise the peculiar "SyntaxError" — which implies determining at parse time whether a give obj.#thing is valid): is it only accessible through this.#foo? That is, if I have a class with a member function that takes another instance of the same class, is JavaScript going to tell me that I can't access private fields, despite those being on the current class? (This is fairly different from most languages, and makes some things impossible to express while keeping internals private.)


First, about accessing private fields on members of the same class: the spec will allow this via `other.#foo`.

The reason I said that the difference between `object.foo` and `object.#foo` is not purely syntax is because they are two completely different actions. The first is a lookup in the object's property map/prototype chain. The second is a private field lookup.

`object.foo`:

  1. Check to see if there's a property named "foo" in `object`'s property map.
    1a. If yes, return the value.
    1b. If no, continue.
  2. Does this object have a prototype? 
    2a. If no, return undefined.
    2b. If yes, repeat these steps starting from 1 using this object's prototype.
`object.#foo`:

  1. Test to see if you're in a class.
    1a. If no, throw a Syntax Error.
    1b. If yes, continue.
  2. Test to see if `object` is an instance of this class.
    2a. If no, throw a Syntax Error.
    2b. If yes, continue.
  3. Test to see if the class defines a private field *#foo*.
    3a. If no, throw a Syntax Error ? (Not positive on this one, it might just return undefined).
    3b. If yes, continue.
  4. Look up this class' private fields for `object`.
  5. Get the value for *#foo*. 
  
In case it wasn't clear: the private field `object.#foo` is NOT a property on `object` named `foo` and marked private. It is a field which exists in a namespace only accessible to the class definition. Without the # sigil, there'd be two issues. See [0] for a pseudo example of how private fields really behave.

The first issue comes from a decision made in the spec by the committee: private fields must not interfere with object properties. This essentially means that an object can have the private field #foo AND the object property "foo" (as I described here [1]). Without the #, the fields would have to exist in the same namespace as the object's properties. If you error out when `object.foo` is accessed outside of the class definition, it would not fit the spec's definition of "private". [2] [3]

The second issue is that without the #, the compiler would need to determine at the call site which lookup method to use, and they decided this would incur too much overhead on every single lookup in the already complicated property lookup logic.

0: https://news.ycombinator.com/item?id=18707421 1: https://news.ycombinator.com/item?id=18706363 2: https://github.com/tc39/proposal-class-fields/blob/master/PR... 3: https://github.com/tc39/proposal-class-fields/blob/master/PR...


>This is because a private field, as defined in the spec, must not interfere with object properties.

Why couldn't it? E.g why not let it interfere...




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: