ES6 problem with private name objects syntax

# Maciej Jaros (10 years ago)

To my understanding private name objects are supposed to make private properties and functions available for new classes syntax in ECMAScript 6 standard.

But the syntax is rather strange:

var myPrivate = new Name();
class Test {
      constructor(foo) {
           this[myPrivate] = foo;
      }
}

I understand the motivation - using just this[myPrivate] wouldn't work because it could be inconsisten when myPrivate is a string variable. If myPrivate='abc' then this[myPrivate] is equivalent this.abc... So that is the main reason Name objects were born, right?

BUT what is the point of having this new syntax if I need to predefine all private variables (also the ones used for methods)?

Instead of above I could just use (shorter, more intuitive, already works):

var myPrivate;
class Test {
      constructor(foo) {
           myPrivate = foo;
      }
}

I could also secure the scope which would still be shorter for more then one variable:

(function(){
var myPrivate, myPrivate2;
class Test {
      constructor(foo) {
           myPrivate = foo;
           myPrivate2 = foo.toString();
      }
}
})()

I'm probably missing some optimization points but I was unable to find them on ES Wiki. The only new thing is the Name object. I see no use case for it and it doesn't seem to be more readable then current solution.

I like this at variable is more readable (aviable in one of the proposals), but it sound wrong when you read it - this-at-variable is wrong (variable is at this, not the other way around). So to make it sound right one could use this#variable or maybe even this##variable. Because "hash-hash variable", or to be more exact "hush-hush variable" is exactly what we mean. And as "#" is already reserved then it seem like a perfect candidate. There is no clash with previous syntax and no Name objects are needed. If browsers or other JS-like engines want to use them internally they should still be able to do so (pre-parse new syntax and add Name objects as needed).

What I'm saying is - please consider dropping Name objects and use some new syntax (e.g. this#variable) to avoid clashes but make declarations more readable for humans.

Also note that var someName = new Name(); ... this[someName] is actually longer then syntax from previous proposal: private(this).someName (almost 2 times longer in some cases).

# David Bruant (10 years ago)

Le 08/01/2014 09:59, Maciej Jaros a écrit :

To my understanding private name objects

Note that now their name is "symbol" and not "private name" anymore.

are supposed to make private properties and functions available for new classes syntax in ECMAScript 6 standard.

A "private" keyword will be introduced in ES7. There is still disagreement on the specifics of the semantics.

But the syntax is rather strange:

var myPrivate = new Name();
class Test {
     constructor(foo) {
          this[myPrivate] = foo;
     }
}

I understand the motivation - using just this[myPrivate] wouldn't work because it could be inconsisten when myPrivate is a string variable. If myPrivate='abc' then this[myPrivate] is equivalent this.abc... So that is the main reason Name objects were born, right?

For the sake of making your code easier to write, read and understand, you wouldn't reassign "myPrivate", preferably even declare it with "const" instead of "var".

BUT what is the point of having this new syntax if I need to predefine all private variables (also the ones used for methods)?

It's a temporary setup. A "private" keyword will be introduce and provide runtime-level privacy (as opposed to source-level privacy like TypeScript does)

Instead of above I could just use (shorter, more intuitive, already works):

var myPrivate;
class Test {
     constructor(foo) {
          myPrivate = foo;
     }
}

I could also secure the scope which would still be shorter for more then one variable:

(function(){
var myPrivate, myPrivate2;
class Test {
     constructor(foo) {
          myPrivate = foo;
          myPrivate2 = foo.toString();
     }
}
})()

Does it really already works? It looks to me like your private variables are shared by all instances (while private in class is supposed to be per instance). When the constructor is called twice, only the last values will remain.

I'm probably missing some optimization points but I was unable to find them on ES Wiki.

I believe the wiki is outdated. [1] has a message at the top saying: "This proposal has progressed to the Draft ECMAScript 6 Specification, which is available for review here: specification_drafts. Any new issues relating to them should be filed as bugs at bugs.ecmascript.org. The content on this page is for historic record only and may no longer reflect the current state of the feature described within."

The only new thing is the Name object. I see no use case for it and it doesn't seem to be more readable then current solution.

Per-instance runtime-level privacy. JavaScript lacks this badly. Note that I didn't mention classes. We need privacy even beyond the context of classes. It's possible to achieve it with WeakMap with something along the lines of:

var privateState = new WeakMap();
function createPrivateState(o){
     privateState.set(o, {});
}
function _private(o){ // "private" is a reserved keyword
     return privateState.get(o);
}

class C{
     constructor(yo){
         createPrivateState(this);

         _private(this).yo = yo;
     }

     getYoPlusTwo(){
         return _private(this).yo+2;
     }
}

But performance are certainly attrocious because of the WeakMap lookup by comparison to what it could be if the property was a string or symbol.

What I'm saying is - please consider dropping Name objects and use some new syntax (e.g. this#variable) to avoid clashes but make declarations more readable for humans.

I can't speak for TC39, but from what I see and read, they're not going to drop symbols. Note that regarding privacy, there is the "relationship" strawman on the table IIRC strawman:relationships I've lost track of what the state of that is.

Last thing I have found [2]: "Sam, Mark and Allen to work on "relationships" and varied representation in ES6."

David

[1] strawman:maximally_minimal_classes [2] rwaldron/tc39-notes/blob/master/es6/2013-03/mar-13.md#conclusionresolution

# Rick Waldron (10 years ago)

On Wed, Jan 8, 2014 at 3:59 AM, Maciej Jaros <egil at wp.pl> wrote:

To my understanding private name objects are supposed to make private properties and functions available for new classes syntax in ECMAScript 6 standard.

But the syntax is rather strange:

var myPrivate = new Name();
class Test {
     constructor(foo) {
          this[myPrivate] = foo;
     }
}

Private names were replaced by the not-private Symbol. Symbol is a symbol, private if you keep it that way and public if you expose it.

I understand the motivation - using just this[myPrivate] wouldn't work because it could be inconsisten when myPrivate is a string variable.

Symbol produces symbols, not strings.

If myPrivate='abc' then this[myPrivate] is equivalent this.abc... So that is the main reason Name objects were born, right?

If the symbol was used to create the property, and the binding undergoes a reassignment, the property won't be accessible via property access by bracket notation:

var o = {};
var s = Symbol();

o[s] = 1;
o[s];
// 1

s = "s";
o[s];
// undefined

You could still get the Symbol by Object.getOwnPropertySymbols(o)... again there is no implied privacy with Symbols.

# Maciej Jaros (10 years ago)

Sorry for not answering sooner...

Rick Waldron (2014-01-08 23:24):

On Wed, Jan 8, 2014 at 3:59 AM, Maciej Jaros <egil at wp.pl <mailto:egil at wp.pl>> wrote:

To my understanding private name objects are supposed to make
private properties and functions available for new classes syntax
in ECMAScript 6 standard.

But the syntax is rather strange:
```
var myPrivate = new Name();
class Test {
     constructor(foo) {
          this[myPrivate] = foo;
     }
}
```

Private names were replaced by the not-private Symbol. Symbol is a symbol, private if you keep it that way and public if you expose it.

I understand the motivation - using just `this[myPrivate]`
wouldn't work because it could be inconsisten when `myPrivate` is
a string variable. 

Symbol produces symbols, not strings.

If `myPrivate='abc'` then `this[myPrivate]` is equivalent
`this.abc`... So that is the main reason Name objects were born,
right?

If the symbol was used to create the property, and the binding undergoes a reassignment, the property won't be accessible via property access by bracket notation:

var o = {}; var s = Symbol();

o[s] = 1; o[s]; // 1

s = "s"; o[s]; // undefined

So basically one could implement Symbol as something similar to GUID generator, right? It should work even if you simply restart a counter and make sure you don't clash with other stuff and e.g. return "__#symbol#1", "#symbol#__2" and so on.

You could still get the Symbol by Object.getOwnPropertySymbols(o)... again there is no implied privacy with Symbols.

And if you can easily get those symbols then why bother? Why not just use "o._s = 1;" (i.e. use some character as a convention to mark private members - as in Python).

I'm sorry for asking stupid questions, but I'm writing a thesis and just trying to understand what is the current state and where is this going to. My understanding was that the key goal at first was the readability of the code. This somehow got shifted to simplicity and minimalism. Not sure what the current goal is. It seems like members visibility in a traditional, declarative sense was just omitted and is shifting to using as less of new symbols and keywords as possible.

, Maciej Jaros.

# Brendan Eich (10 years ago)

Maciej Jaros wrote:

So basically one could implement Symbol as something similar to GUID generator, right? It should work even if you simply restart a counter and make sure you don't clash with other stuff and e.g. return "__#symbol#1", "#symbol#__2" and so on.

No. There must be no way, by guessing or luck, to spell a symbol-named property using a string.