class-private syntax in ES6 (was: ES6, ES7, ES8 and beyond. A Proposed Roadmap.)

# Brendan Eich (11 years ago)

Mark S. Miller wrote:

  • Completing the class design
    • at least high integrity and private state

If I'm not mistaken, we need class-private syntax for classes to have ultimate double-blind consensus in ES6. See last meeting notes.

At JQueryUK, I threw up a sketch in slides based on strawman:relationships:

class SkinnedMesh extends THREE.Mesh{
    private identityMatrix,
            bones,
            boneMatrices;

    constructor(geometry,  materials)  {
        super(geometry,  materials);

        this@identityMatrix = new  THREE.Matrix4();
        this@bones = [];
        this@boneMatrices = [];
        ...
    }

    ...
}

The TypeScript (CoffeeScript had it already, and more concisely via @) option to declare and initialize via a private prefix on one of constructor's parameters would be helpful to many developers:

class  Point{
   constructor(private x, private y) {}
   add(other) {
     return Point(this@x + other@x, this@y + other@y);
   }
   ...
}

I hope we can agree to do this much for ES6, based on the relationships work, which I'd like to thank Tom and you for championing. At first I thought it was not helpful, but then the lightbulb went off ;-).

# Brian Di Palma (11 years ago)

Another mail that I expected to receive more attention that hasn't...

We're London based so we had attendants at JQueryUK and the announcement of private class state in ES6 was a surprise, a pleasant one but still surprising.

Is it the case that the announcement was jumping the gun?

Needless to say for programming with large code bases it would be excellent to have private state.

From the meeting notes thought it does not seem as if this has been agreed to.

YK: So, what is your proposal?

MM:

My proposal is the private symbols get postponed to ES7 WeakMap gets renamed to reflect the inverted thinking If we adopt the @ syntax in ES6, I want to be able to use a WeakMap on the right side

...Don't care so much about the renaming, but feel that it could add clarity to the feature

RW: (Disagree based on experience teaching the concept)

WH: no consensus on class without private symbols

MM: Rick, can you find the history of this?

RW: (recounts two meetings where Waldemar was not present, but a general consensus existing with the understanding that Waldemar would still have something to say. At Northeasten, Allen presented @-names, in which Waldemar found to sufficiently meet his privacy requirement for classes)

...Discussion around class private state as a whole.

BE: We need to synthesize what's going into ES6. Waldemar claims this must include some way of adding class private state.

STH: I would like to stop this conversation and allow myself time to think about this.

BE: Done.

Conclusion/Resolution

Sam, Mark and Allen to work on "relationships" and varied representation in ES6.

The @ syntax is not the nicest but it does highlight private state which is probably a good thing. I'd happily type "IAMTHEWALRUS" if it gave me private state. Well not happily; but I'd still type it.

From the notes it does not seem clear if a lack of private is enough to scupper classes altogether.

That would seem an extreme step to take, surely private state can be added in ES7?

# Brendan Eich (11 years ago)

Brian Di Palma wrote:

Another mail that I expected to receive more attention that hasn't...

For some reason my mail program doesn't thread your reply to my o.p. Here it is in the archive, FWIW:

esdiscuss/2013-April/029969

We're London based so we had attendants at JQueryUK and the announcement of private class state in ES6 was a surprise, a pleasant one but still surprising.

Is it the case that the announcement was jumping the gun?

Rembmer, my words were that "I threw up a sketch" -- not a final masterpiece, not the Mona Lisa.

However as your meeting notes excerpts show, we still don't quite have consensus on classes per se, without including private syntax in ES6.

This is an agenda item for the upcoming TC39 meeting. We should try to build on the work by Mark and Tom at

strawman:relationships

and make progress, whether that work ends up in ES6 or ES7 for prudential reasons.

Needless to say for programming with large code bases it would be excellent to have private state.

Agreed!

# Rick Waldron (11 years ago)

On Sun, Apr 28, 2013 at 3:16 PM, Brendan Eich <brendan at mozilla.com> wrote:

Brian Di Palma wrote:

Another mail that I expected to receive more attention that hasn't...

@Brian, This is the second time you've opened a thread reply with a rebuke regarding (lack of) speedy of response. Just saying...

For some reason my mail program doesn't thread your reply to my o.p. Here it is in the archive, FWIW:

mail.mozilla.org/**pipermail/es-discuss/2013-**April/029969.htmlesdiscuss/2013-April/029969

We're London based so we had attendants at JQueryUK and the announcement

of private class state in ES6 was a surprise, a pleasant one but still surprising.

Is it the case that the announcement was jumping the gun?

Rembmer, my words were that "I threw up a sketch" -- not a final masterpiece, not the Mona Lisa.

However as your meeting notes excerpts show, we still don't quite have consensus on classes per se, without including private syntax in ES6.

This is an agenda item for the upcoming TC39 meeting. We should try to build on the work by Mark and Tom at

**doku.php?id=strawman:**relationshipsstrawman:relationships

and make progress, whether that work ends up in ES6 or ES7 for prudential reasons.

Needless to say for programming with large code bases it would be

excellent to have private state.

Agreed!

The introduction of class in ES6 should not be blocked (or postponed until ES7) by a lack of class (specific) private declaration form. I understand and appreciate Brendan's remarks re: double-blind consensus, but politely disagree with the notion that we must produce a specific syntactic form when private state can be achieved with the use of a WeakMap or a Symbol: gist.github.com/rwldrn/5478221

I've always been an @-name supporter and have had a pending revisitation agenda item for the last two meetings, deferred in favor of the bigger fish we had to fry ;)

# Brendan Eich (11 years ago)

We clearly don't quite have consensus, as your interaction at that meeting helped highlight. I'd like to restore consensus, not break it.

What goes into a particular edition of ECMA-262 is less important than making progress on draft emerging-consensus specs for private-in-class, prototype-implemeting, and developer-testing them.

Doing nothing raises the risk of a larger consensus break, but that's the least of it. Doing nothing underserves developers and tends to defer too much thinking about private syntax that we should be doing sooner rather than later.

# David Bruant (11 years ago)

Le 21/04/2013 19:22, Brendan Eich a écrit :

At JQueryUK, I threw up a sketch in slides based on strawman:relationships:

|class SkinnedMesh extends THREE.Mesh{ private identityMatrix, bones, boneMatrices;

constructor(geometry, materials) { super(geometry, materials);

this at identityMatrix=  new  THREE.Matrix4();
this at bones=  [];
this at boneMatrices=  [];
...

}

... }|

Can you provide more details on the semantics of syntax given the relationship strawman? With my understanding of the current proposal:

  • in "this at bones = [];", 'bones' has to be a string or (unique) symbol. I imagine the private syntax makes it a symbol (that will not be access beyond the class scope) for the sake of non-forgeability.
  • by default, objects have no value for @geti nor @seti [1], so following the strawman, "this at bones = [];" should set the value for the symbol. Unfortunately, (unique) symbols are enumerated via reflection, so this is not private.

Sharing my thoughts trying to figure out the semantics you want to provide: Was it implicit that each class declaration creates a @geti/@seti pair as I describe at [2] and attach it to SkinnedMesh.prototype? Hmm... if the pair on the prototype, then it can be shadowed by an outsider via Object.defineProperty. I believe this shadowing will give access to the symbol that was supposed to remain encapsulated any time the @-syntax is used and break privacy. So no prototype. So the last chance is for the class @geti/@seti pair to be assigned as own property to each instances. And preferably make them non-configurable/non-writable properties so they remain where they are. One pair of property per instance may have a cost, but it sounds possible to heavily optimize in memory frozen properties of the same class for the 80% use case. Even as own property, I believe inheritance can be made worked out (a class extending another accesses the inherited class @geti/@seti pair and builds its own pair on top of that. Well-encapsulated symbols won't collide from one class to another).

Was it what you had in mind?

|class Point{ constructor(private x, private y) {} add(other) { return Point(this at x + other at x, this at y + other at y); } ... } |

I'm guessing explanations to the above will lighten up my understanding of this part, but in case there is something non-trivial to explain here, I'll take it too.

Thanks,

David

[1] Last answer to Tom of esdiscuss/2013-April/029697 [2] Last answer to Tom of esdiscuss/2013-April/029700

# Mark S. Miller (11 years ago)

On Sun, Apr 28, 2013 at 2:33 PM, David Bruant <bruant.d at gmail.com> wrote:

Can you provide more details on the semantics of syntax given the relationship strawman? With my understanding of the current proposal:

  • in this at bones = [];, bones has to be a string or (unique) symbol. I imagine the private syntax makes it a symbol (that will not be access beyond the class scope) for the sake of non-forgeability.
  • by default, objects have no value for @geti nor @seti [1], so following the strawman, this@bones = []; should set the value for the symbol. Unfortunately, (unique) symbols are enumerated via reflection, so this is not private.

Sharing my thoughts trying to figure out the semantics you want to provide: Was it implicit that each class declaration creates a @geti/@seti pair as I describe at [2] and attach it to SkinnedMesh.prototype? Hmm... if the pair on the prototype, then it can be shadowed by an outsider via Object.defineProperty. I believe this shadowing will give access to the symbol that was supposed to remain encapsulated any time the @-syntax is used and break privacy. So no prototype. So the last chance is for the class @geti/@seti pair to be assigned as own property to each instances. And preferably make them non-configurable/non-writable properties so they remain where they are. One pair of property per instance may have a cost, but it sounds possible to heavily optimize in memory frozen properties of the same class for the 80% use case. Even as own property, I believe inheritance can be made worked out (a class extending another accesses the inherited class @geti/@seti pair and builds its own pair on top of that. Well-encapsulated symbols won't collide from one class to another).

Was it what you had in mind?

Hi David, I'll be brief because I have little time today. And I probably won't follow up on any responses until another day -- just so you'll know. But you drifted quite far from what the relationship strawman has in mind. The example above would act approximately as if written

let SkinnedMesh = (function(){
    const identityMatrix = WeakMap();
    const bones = WeakMap();
    const boneMatrices = WeakMap();

    function SkinnedMesh(geometry,  materials) {
        THREE.Mesh.call(this, geometry,  materials);

        identityMatrix[@seti](this, new THREE.Matrix4());
        bones[@seti](this, []);
        bonesMatrices[@seti](this, []);
        ...
    }
    SkinnedMesh.__proto__ = THREE.Mesh; // more on __proto__ later
    SkinnedMesh.prototype = Object.create(THREE.Mesh.prototype);
    ...
    return SkinnedMesh;
}).call(this);

Where "WeakMap" may be renamed something more intuitive for this role. Does this clear things up?

# David Bruant (11 years ago)

Le 29/04/2013 00:32, Mark S. Miller a ?crit :

Does this clear things up?

ooooooohh.... Yes it does. I hadn't thought of WeakMaps for the private syntax. Sounds good then.

# Brendan Eich (11 years ago)

David Bruant wrote:

ooooooohh.... Yes it does. I hadn't thought of WeakMaps for the private syntax. Sounds good then.

Another point Mark and Tom made that I found helpful:

The traditional GC-costly WeakMap implementation, which handles cases where the map and its keys' lifetimes are not related in any particular way, to perform cycle collection treating each key/value entry as an Ephemeron, is not required for private-in-class. So long as the class lives, its private names must work. Instances keep their class alive; new instances may be created even if old ones were all GC'ed. Symbols are no more leaky that WeakMaps in this setting.

This means that private-in-class names can be per-class as Mark showed, but more: the private values may be stored in fields of each instance. No WeakMap at full GC cost is required. Whether the implementation uses Symbols or GC-optimized WeakMaps is not observable.

As the strawman notes, these private variables's names and values cannot be discovered by reflection.

Given all this, I saw light at the end of the tunnel, and sketched accordingly in my JQueryUK talk. I tagged the slide's title with "(ES6?)" -- note the "?" where elsewhere I used "(ES6)" or "(ES7)"

# Brian Di Palma (11 years ago)

My apologies, I didn't mean it as a rebuke ( although looking at what I wrote I can understand the thought ). I was a bit unsure about floating back up another email like this when it seemed people maybe weren't interested in the topic. Obviously I did an awful job at conveying that feeling. Consider myself chastened!

Interesting gists, especially the use of WeakMap.

# Rick Waldron (11 years ago)

On Sun, Apr 28, 2013 at 4:23 PM, Rick Waldron <waldron.rick at gmail.com>wrote:

On Sun, Apr 28, 2013 at 3:16 PM, Brendan Eich <brendan at mozilla.com> wrote:

Brian Di Palma wrote:

Another mail that I expected to receive more attention that hasn't...

@Brian, This is the second time you've opened a thread reply with a rebuke regarding (lack of) speedy of response. Just saying...

For some reason my mail program doesn't thread your reply to my o.p. Here it is in the archive, FWIW:

mail.mozilla.org/**pipermail/es-discuss/2013-**April/029969.htmlesdiscuss/2013-April/029969

We're London based so we had attendants at JQueryUK and the announcement

of private class state in ES6 was a surprise, a pleasant one but still surprising.

Is it the case that the announcement was jumping the gun?

Rembmer, my words were that "I threw up a sketch" -- not a final masterpiece, not the Mona Lisa.

However as your meeting notes excerpts show, we still don't quite have consensus on classes per se, without including private syntax in ES6.

This is an agenda item for the upcoming TC39 meeting. We should try to build on the work by Mark and Tom at

**doku.php?id=strawman:**relationshipsstrawman:relationships

and make progress, whether that work ends up in ES6 or ES7 for prudential reasons.

Needless to say for programming with large code bases it would be

excellent to have private state.

Agreed!

The introduction of class in ES6 should not be blocked (or postponed until ES7) by a lack of class (specific) private declaration form. I understand and appreciate Brendan's remarks re: double-blind consensus, but politely disagree with the notion that we must produce a specific syntactic form when private state can be achieved with the use of a WeakMap or a Symbol: gist.github.com/rwldrn/5478221

Mark Miller and I had an offline discussion that clarified for me that the example using a symbol as a property key would allow the value to be discovered via ES6's Object.getOwnPropertyKeys() which returns the result of the internal [[OwnPropertyKeys]] method. The mistake I had made was assuming that where [[OwnPropertyKeys]] mentions "private Symbol" that it actually just meant the thing one Symbol that is just a Symbol—which is incorrect.

# Brendan Eich (11 years ago)

Rick Waldron wrote:

Mark Miller and I had an offline discussion that clarified for me that the example using a symbol as a property key would allow the value to be discovered via ES6's Object.getOwnPropertyKeys() which returns the result of the internal [[OwnPropertyKeys]] method. The mistake I had made was assuming that where [[OwnPropertyKeys]] mentions "private Symbol" that it actually just meant the thing one Symbol that is just a Symbol?which is incorrect.

Sorry, I didn't follow the last sentence -- but the first confused me too. We haven't finished ES6 yet, and Object.getOwnPropertyKeys is new. We can decide what it reveals, e.g., whether it censors private symbols. But only if we add private symbols as a variation on symbols.

The relationships work is in my view about enabling private syntax to map to something that could be implemented by GC-optimized WeakMaps or (essentially) private symbols. That seems like a win, since we're designing for users first, not implementors (and implementors can certainly cope, lots of options). Users want class-private (and module-private?) syntax.

What proxies do is an open issue, but the relationships strawman lists some options.

I've always been an @-name supporter and have had a pending revisitation agenda item for the last two meetings, deferred in favor of the bigger fish we had to fry ;)

Some of us on TC39 don't like the @-name proposal, it's too chatty, requires too much boilerplate. This was among the reasons given when we deferred it.

The relationships' strawman infix-@ operator, combined with uncontroversial private declaration syntax (including, I believe this is uncontroversial too, constructor formal parameter prefixing with private to declare and initialize) looks to be both more concise and sufficient for the use-cases we've aspired to serve.

# David Bruant (11 years ago)

Le 29/04/2013 18:09, Brendan Eich a écrit :

Users want class-private (and module-private?) syntax.

I'm not up-to-date on the module work, but last I looked at it, "module private" is everything except what is explicitly exported, no? (which is a good thing, I believe)

# Brendan Eich (11 years ago)

David Bruant wrote:

Le 29/04/2013 18:09, Brendan Eich a ?crit :

Users want class-private (and module-private?) syntax. I'm not up-to-date on the module work, but last I looked at it, "module private" is everything except what is explicitly exported, no? (which is a good thing, I believe)

This isn't clear for nested modules, or wasn't when they were discussed last.

The big win of private as a declarative keyword would be its short-hand for const _ = Symbol(), combined with checked uses on right of @.