shortcuts for defining block-local private names, plays nicely with @foo syntax

# Herby Vojčík (13 years ago)

Hello,

since @-prefixed syntax to access private-named properties seems to win in the private grounds (and it is good thing), I'd like kill two birds with one stone:

  • private keyword seemed to lose its role
  • to access property via @foo, I must 'let foo = Name.create()' first

So let us allow: ... { private foo, bar; ... agent. at foo = ...; ... more uses of @foo and @bar ... } in imperative (code-containing, semicolon-delimited) blocks and ... { private [foo, bar], ... @foo: Date.now(), @bar: cowboys.length, ... aMethod () { ... use @foo and @bar } } in declarative (data-describing, comma-delimited) blocks.

In both cases let it be the declaration of (one-time lexical block-local) private names foo and bar. For any curly block. Without need to define these singletons explicitly and wrap them so they are only visible where due,

# Brendan Eich (13 years ago)

This was already proposed. See the whole strawman, but in particular these sections:

strawman:private_names#the_private_declaration, strawman:private_names#private_declaration_scoping, strawman:private_names#private_declarations_exist_in_a_separate_name_space_parallel_to_the_variable_binding_environment

The last really was too much for some folks. It makes the meaning of an identifier after . or before : in an object literal depend on a binding declaration, possibly far above.

We could revive this, but deferring it and simplifying led to

harmony:private_name_objects

which is in ES6.

# Herby Vojčík (13 years ago)

Brendan Eich wrote:

This was already proposed. See the whole strawman, but in particular these sections:

strawman:private_names#the_private_declaration

strawman:private_names#private_declaration_scoping

strawman:private_names#private_declarations_exist_in_a_separate_name_space_parallel_to_the_variable_binding_environment

The last really was too much for some folks. It makes the meaning of an identifier after . or before : in an object literal depend on a binding declaration, possibly far above.

Thank you. I did not know of these. The problem in the third one (and the solution) are really crazy... I would do the early error if there would be a clash (akin to double let).

We could revive this, but deferring it and simplifying led to

harmony:private_name_objects

I was not trying to revive them (not even after reading part of them). I was reacting to actual situation, that being: privates should be realized through foo. at bar syntax, where bar is identifier (must be declared in some scope) and must have name.create() as its value.

Definitely there can be some cases where explicitly creating name.value() and playing with it is beneficial, but most of the time (imnsho) it's the case that you need to use name.create() just as a key in foo. at bar. You should restrict the scope where it is known, and not to "export" it, since your "privacy" is gone.

The solution that spring to mind is straightforward the use of now-orphaned private keyword for it seems just right. I only proposed (as of actual situation, not as revival of old strawman; as a shortcut for actual calling name.create() at the start of the program or simulated in compilation phase) to use private to declare such identifiers, each pre-filled with name.create() once, with block visibility.

For foo. at bar it is very convenient. I really believe big percentage of name.create() is of this sort. Not going against harmony:private_name_objects, just add a convenient use.

# Brendan Eich (13 years ago)

Herby Vojčík <mailto:herby at mailbox.sk> January 21, 2012 1:33 PM Brendan Eich wrote:

This was already proposed. See the whole strawman, but in particular these sections:

strawman:private_names#the_private_declaration

strawman:private_names#private_declaration_scoping

strawman:private_names#private_declarations_exist_in_a_separate_name_space_parallel_to_the_variable_binding_environment

The last really was too much for some folks. It makes the meaning of an identifier after . or before : in an object literal depend on a binding declaration, possibly far above.

Thank you. I did not know of these. The problem in the third one (and the solution) are really crazy... I would do the early error if there would be a clash (akin to double let).

The way to resolve the two-lexical-binding-chains issue for private declarations is not to overload . (member expression; also : in object literals), by requiring @ instead:

private foo;

@foo = bar; // this-relative private foo

return @foo === other. at foo;

return {@foo: bar};

I think we may be pretty close to consensus on this, but I'm not sure. Not in ES6 at this point.

The solution that spring to mind is straightforward the use of now-orphaned private keyword for it seems just right. I only proposed (as of actual situation, not as revival of old strawman; as a shortcut for actual calling name.create() at the start of the program or simulated in compilation phase) to use private to declare such identifiers, each pre-filled with name.create() once, with block visibility.

For foo. at bar it is very convenient. I really believe big percentage of name.create() is of this sort. Not going against harmony:private_name_objects, just add a convenient use.

I quite agree. Requiring Name.create() or new Name() all over is a drag. We should keep honing in on more convenient private name object binding-declaration and binding-use syntax.

# Herby Vojčík (13 years ago)

Brendan Eich wrote:

Herby Vojčík <mailto:herby at mailbox.sk> January 21, 2012 1:33 PM Brendan Eich wrote:

strawman:private_names#private_declarations_exist_in_a_separate_name_space_parallel_to_the_variable_binding_environment

The last really was too much for some folks. It makes the meaning of an identifier after . or before : in an object literal depend on a binding declaration, possibly far above.

Thank you. I did not know of these. The problem in the third one (and the solution) are really crazy... I would do the early error if there would be a clash (akin to double let).

The way to resolve the two-lexical-binding-chains issue for private declarations is not to overload . (member expression; also : in object literals), by requiring @ instead:

private foo;

@foo = bar; // this-relative private foo

return @foo === other. at foo;

return {@foo: bar};

This helps a lot, but there still is (I only proposed a convenient shortcut, not some magic special names for private names) an identifier foo having that private name in its value. So it would clash if foo was defined in code. But I believe that this can be solved by applying analogies from let, var, scopes, shadowing etc. all that machinery.

I think we may be pretty close to consensus on this, but I'm not sure. Not in ES6 at this point.

Well, I am pretty hoping for this. It makes thing much more straightforward (when compared to private in actual class proposal with private store etc. - private names work and are generic).

# Brendan Eich (13 years ago)

Herby Vojčík <mailto:herby at mailbox.sk> January 21, 2012 1:56 PM Brendan Eich wrote:

Herby Vojčík <mailto:herby at mailbox.sk> January 21, 2012 1:33 PM Brendan Eich wrote:

strawman:private_names#private_declarations_exist_in_a_separate_name_space_parallel_to_the_variable_binding_environment

The last really was too much for some folks. It makes the meaning of an identifier after . or before : in an object literal depend on a binding declaration, possibly far above.

Thank you. I did not know of these. The problem in the third one (and the solution) are really crazy... I would do the early error if there would be a clash (akin to double let).

The way to resolve the two-lexical-binding-chains issue for private declarations is not to overload . (member expression; also : in object literals), by requiring @ instead:

private foo;

@foo = bar; // this-relative private foo

return @foo === other. at foo;

return {@foo: bar};

This helps a lot, but there still is (I only proposed a convenient shortcut, not some magic special names for private names) an identifier foo having that private name in its value.

This was not decided, as far as I know. There are two choices:

  1. "private foo;" defines a lexical binding used to denote the private name object, as well as after @ to use it to access a property in an object.

  2. Rather, the only places foo would be allowed after "private foo;" above are those after an @. IOW it would be fine to use "let foo = 42;" and "private foo;" without conflict. Some further syntax, a la the old #.foo proposal (obsoleted in terms of # now), would be required to reflect foo from lexical-to-the-right-of-@ space into a first-class private name object reference.

So it would clash if foo was defined in code. But I believe that this can be solved by applying analogies from let, var, scopes, shadowing etc. all that machinery.

I'm not sure what you mean. Choice (1) above allows shadowing. Choice (2) doesn't have any conflict.

I think we may be pretty close to consensus on this, but I'm not sure. Not in ES6 at this point.

Well, I am pretty hoping for this. It makes thing much more straightforward (when compared to private in actual class proposal with private store etc. - private names work and are generic).

I may be overoptimistic about consensus. The choice (1) vs. (2) remains open, IIRC.

# Herby Vojčík (13 years ago)

Brendan Eich wrote:

Herby Vojčík <mailto:herby at mailbox.sk> January 21, 2012 1:56 PM Brendan Eich wrote:

private foo;

@foo = bar; // this-relative private foo

return @foo === other. at foo;

return {@foo: bar};

This helps a lot, but there still is an identifier foo having that private name in its value.

This was not decided, as far as I know. There are two choices:

  1. "private foo;" defines a lexical binding used to denote the private name object, as well as after @ to use it to access a property in an object.

  2. Rather, the only places foo would be allowed after "private foo;" above are those after an @. IOW it would be fine to use "let foo = 42;" and "private foo;" without conflict. Some further syntax, a la the old #.foo proposal (obsoleted in terms of # now), would be required to reflect foo from lexical-to-the-right-of-@ space into a first-class private name object reference.

Oh. I favor 1. Inspired by latest notes and for(let...) I would see { private foo; ... } desugared to { let foo = _the_real_foo; ... } where _the_real_foo is defined somewhere at the module or program level such that it will not clash (hardwired private name or index to a table or whatever) and the rest is just reusing existing rules.

  1. is too magical (for me).
# Brendan Eich (13 years ago)

Herby Vojčík <mailto:herby at mailbox.sk> January 21, 2012 2:21 PM Oh. I favor 1. Inspired by latest notes and for(let...) I would see { private foo; ... } desugared to { let foo = _the_real_foo;

Er, const, I hope -- not let. Right?

# Brendan Eich (13 years ago)

Brendan Eich <mailto:brendan at mozilla.org> January 21, 2012 4:39 PM

Er, const, I hope -- not let. Right?

And _the_real_foo should be expanded:

{ private foo; ... }

desugars to

{ const foo = Name.create("foo"); ... }

with Name.create imported appropriately.

# Herby Vojčík (13 years ago)

Brendan Eich wrote:

Herby Vojčík <mailto:herby at mailbox.sk> January 21, 2012 2:21 PM Oh. I favor 1. Inspired by latest notes and for(let...) I would see { private foo; ... } desugared to { let foo = _the_real_foo;

Er, const, I hope -- not let. Right?

Of course. My mistake.

# Herby Vojčík (13 years ago)

Brendan Eich wrote:

And _the_real_foo should be expanded:

{ private foo; ... }

desugars to

{ const foo = Name.create("foo"); ... }

with Name.create imported appropriately.

No, I though more in lines of:

// singleton code, in module level / program level // generated from all private occurences: const prvTable = Name.create(); // prvTable being hardwired somehow so it does not clash // and of course hidden from user @prvTable = [ Name.create(), Name.create(), ... // n times when n is number of privates ];

// and the bocks desugared to { const foo = module. at prvTable[42]; // module. at prvTable is just a hint for // "somehow, get to the private table" // it is up to implementation // 42 is just the example index ... }

with Name.create imported appropriately.

# Herby Vojčík (13 years ago)

Brendan Eich wrote:

And _the_real_foo should be expanded:

{ private foo; ... }

desugars to

{ const foo = Name.create("foo");

BTW, would this not mean it is different in every run?

# Brendan Eich (13 years ago)

I suspect your very complicated translation with prvTable etc. is intended to hoist private somehow, once per declaration in source rather than once per evaluation of declaration. That's too restrictive, since private declarations can be placed in outer blocks or closures for singleton naming, or moved into inner constructor-like functions for per-instance private names.

Users should be able to declare class-private and instance-private names, in other words.

Your block examples, which I modified, are not complete enough to judge what's wanted. By asserting singleton private name per source declaration you are deciding prematurely and overconstraining the feature. Let the user put the block or closure at the right inner or outer level and declare there. There are an arbitrary number of generative layers (generations): class static private, class instance private, inner closure private, etc. etc.

# Herby Vojčík (13 years ago)

Brendan Eich wrote:

I suspect your very complicated translation with prvTable etc. is intended to hoist private somehow, once per declaration in source rather than once per evaluation of declaration. That's too restrictive, since

Exactly. By design.

private declarations can be placed in outer blocks or closures for singleton naming, or moved into inner constructor-like functions for per-instance private names.

I proposed private to really only do the conventional per-source singleton aliasing (I dubbed 'const foo = perSourceTable[index]' aliasing for this discussion).

The motivation for this is exactly the "can be placed in outer blocks or closures". My proposal for 'private' is precisely and only to create conventional way to do these singletons without need for those annoying wrappers.

Maybe I should include the example to illustrate how hard and inconcievable it is to create such singleton for use in a few { levels deeper, going there and back, creating them more for many nested levels in one outer place, and so forth, but I believe you can imagine.

Users should be able to declare class-private and instance-private names, in other words.

Instance-private: These cases do not need any special syntax. They can use const foo = Name.create(). It is very little hassle. I proposed 'private' only for singletons, because for them the convenience is really useful.

Class-private: Use singleton in class block scope.

Your block examples, which I modified, are not complete enough to judge what's wanted. By asserting singleton private name per source declaration you are deciding prematurely and overconstraining the feature. Let the user put the block or closure at the right inner or

It was meant as a convenience only for singletion, as they are the hard case. The other cases are easy without need for help from 'private'.

So user can put the local case there, by normal means. Or he can put the hard case (singletion with wrapper) with conenient 'private'.

outer level and declare there. There are an arbitrary number of generative layers (generations): class static private, class instance private, inner closure private, etc. etc.

And I say (and hopefully I am not mistaken) that those runtime-local are easy to do by playing with let, const and Name.create(); and those lexically-local are hard so the convenience is placed especially for them.

Also, I'd say, the semantics of private can then be straightforward: for any {...} block, the private key is only created once and visible only in the block. Never mind what block will it be; you have the spatially local temporally shared key for your use.

# Allen Wirfs-Brock (13 years ago)

On Jan 21, 2012, at 12:07 PM, Brendan Eich wrote:

This was already proposed. See the whole strawman, but in particular these sections:

strawman:private_names#the_private_declaration, strawman:private_names#private_declaration_scoping, strawman:private_names#private_declarations_exist_in_a_separate_name_space_parallel_to_the_variable_binding_environment

The last really was too much for some folks. It makes the meaning of an identifier after . or before : in an object literal depend on a binding declaration, possibly far above.

We could revive this, but deferring it and simplifying led to

harmony:private_name_objects

which is in ES6.

There has also been a number of discussion threads here about syntax for private name access.

I personally have come to the conclusions that

obj. at foo

would be a better than

obj[foo]

for accessing a property of obj that is keyed by the private name that is the value of the foo binding.

My impression, is that a number of other participants in these discussion share this opinion. These are various reasons for this preference, including pleasantness, experience from CoffeeScript and a desire (rationalize in strawman:object_model_reformation ) to strongly distinguish routine structural property access from dynamically computed data key accesses.

The plan of record is that ES6 will support the creation of private named properties in object literals using syntax like this:

const foo = name.create(); let obj = { [foo]: 42 };

However, if @foo is going to be used for private named member accesses instead of [foo] then it also makes sense to use @ instead of [ ] in object literal property definitions. In that case, we should replace the above with:

const foo = name.create(); let obj = { @foo: 42 };

Note that this doesn't run into any of the scoping or multiple name space issues that were raised as objections to the original private name proposals liked above. Also it doesn't preclude use of [ ] to access private names. You could still say either obj[foo] or obj. at foo to access the properties whose key is the value of foo

I plan on proposing at the next TC39 meeting that we support .@ member accesses and that we replace the use of [expr ] to define private named properties in object literals ( harmony:object_literals#object_literal_computed_property_keys ) with @identifier to define such properties.

Regardless of whether this proposal flies we could consider supporting:

private foo,bar;

as a short hand for:

//assume already done: import name as "@names";
const foo=name.create(), bar=name.create();

I think this would be a desirable addition, but I don't want it to be a make or break issue for the .@ proposal.

There are a couple of decision that still need to make for this proposal:

  1. should .@ member access and @ object literal property definitions permit he property key to be any toString-able value and not just private name values? The current plan of record does not require a private name value in the analogous contexts. I'm slightly inclined towards requiring private name values, but would be happy either way.

  2. elimination of arbitrary expression as direct keys in object literal property definitions:

The current "computed property keys" proposals allows things like:

for (var n=0;n<10;) { a.push( { ["prop"+n]: n++ }); }

Do we really need to support this sort of computed property name definition? If so, we could probably allow something such as:

for (var n=0;n<10;) { a.push( { @("prop"+n): n++ }); }

I'm include to not supporting the such arbitrary expressions in such property definitions, particularly if 1) above is decided as no. Then this could be expressed as

for (var n=0;n<10;) { let k = "prop"+n; a.push( { @k: n++ }); }

  1. should @foo as a primary expression be interpreted as this. at foo

I think it should, but note that this means that

const foo = name.create(); let obj = { @foo: @foo };

would mean the same as:

const foo = name.create(); let obj = { @foo: this. at foo /key and value probably different values };

rather than:

const foo = name.create(); let obj = { @foo: foo //key and value are the same value };

This might be a source of confusion for some JS programmers.

Thoughts?

# Tab Atkins Jr. (13 years ago)

On Sun, Jan 22, 2012 at 4:31 PM, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:

I personally have come to the conclusions that

obj. at foo

would be a better than

obj[foo]

for accessing a property of obj that is keyed by the private name that is the value of the foo binding.

My impression, is that a number of other participants in these discussion share this opinion.  These are various reasons for  this preference, including pleasantness, experience from CoffeeScript and a desire (rationalize in strawman:object_model_reformation ) to strongly distinguish routine structural property access from dynamically computed data key accesses.

I have a question, that may be an objection. In my blog post www.xanthir.com/blog/b4FJ0, I demonstrate several example

usages of Names. Most of them involve using a Name that's hung off of another object. Is there a way to support this pattern without a temporary variable?

For example, from my post:

myCoolObject.prototype[Iterator.getIterator] = function(){...}

Using @ for access, would "myCoolObject.prototype. at Iterator.getIterator = function(){...}" work, or would that attempt to retrieve a property using "Iterator" as a Name, then retrieve the "getIterator" property of that?

If the latter, this is rather inconvenient for what I expect will be common patterns.

The plan of record is that ES6 will support the creation of private named properties in object literals using syntax like this:

const foo = name.create(); let obj = {    [foo]: 42 };

However, if @foo is going to be used for private named member accesses instead of [foo] then it also makes sense to use @ instead of [ ] in object literal property definitions. In that case, we should replace the above with:

const foo = name.create(); let obj = {    @foo: 42 };

Note that this doesn't run into any of the scoping or multiple name space issues that were raised as objections to the original private name proposals liked above.  Also it doesn't preclude use of [ ] to access private names. You could still say either    obj[foo] or obj. at foo to access the properties whose key is the value of foo

Regardless of the answer above, this seems to allow the actual usage in my post, which is nice. But it appears that it will be impossible to use the pattern I cite in an object literal without assigning it to a temporary variable. Is this correct?

  1. should .@ member access and @ object literal property definitions permit he property key to be any toString-able value and not just private name values?  The current plan of record does not require a private name value in the analogous contexts. I'm slightly inclined towards requiring private name values, but would be happy either way.

I don't understand what the use of a toString-able value would be in the context of a private variable, since you can only store private things with Names.

  1. elimination of arbitrary expression as direct keys in object literal property definitions:

The current "computed property keys" proposals allows things like:

for (var n=0;n<10;) {    a.push( {       ["prop"+n]: n++    }); }

Do we really need to support this sort of computed property name definition?  If so, we could probably allow something such as:

for (var n=0;n<10;) {    a.push( {      @("prop"+n): n++    }); }

I'm include to not supporting the such arbitrary expressions in such property definitions, particularly if 1) above is decided as no.  Then this could be expressed as

for (var n=0;n<10;) {    let k = "prop"+n;    a.push( {      @k: n++    }); }

This seems related to my concern above, except that this example uses string-valued variables rather than Names.

  1. should @foo as a primary expression be interpreted as this. at foo

I think it should, but note that this means that

const foo = name.create(); let obj = {    @foo: @foo };

would mean the same as:

const foo = name.create(); let obj = {    @foo: this. at foo  /key and value probably different values };

rather than:

const foo = name.create(); let obj = {    @foo: foo  //key and value are the same value };

This might be a source of confusion for some JS programmers.

I suspect that either would be confusing. I agree with you that it's better for @foo to be interpreted as this. at foo.

# Brendan Eich (13 years ago)

Herby Vojčík <mailto:herby at mailbox.sk> January 22, 2012 12:34 PM Brendan Eich wrote:

I suspect your very complicated translation with prvTable etc. is intended to hoist private somehow, once per declaration in source rather than once per evaluation of declaration. That's too restrictive, since

Exactly. By design.

For classes, we have agreed on class-private, rather than instance-private, instance variables. However you don't need such a complex desugaring for classes, and "private x;" not in a class should be evaluated, not hoisted into singleton-hood somehow.

class Point { ... private x, y; ... } // ignore details of whether in constructor or class body

should desugar roughly to

let Point = do { private x, y; class Point { ... ... } };

so as to achieve the class-private instance variable semantics wanted. This does suggest that putting the private declarations in constructor is a mistake, since they would seem to be generated once per construction (instance), not once per class (as class-private wants).

# Brendan Eich (13 years ago)

Allen Wirfs-Brock <mailto:allen at wirfs-brock.com> January 22, 2012 4:31 PM

I personally have come to the conclusions that

obj. at foo

would be a better than

obj[foo]

for accessing a property of obj that is keyed by the private name that is the value of the foo binding.

My impression, is that a number of other participants in these discussion share this opinion. These are various reasons for this preference, including pleasantness, experience from CoffeeScript and a desire (rationalize in strawman:object_model_reformation ) to strongly distinguish routine structural property access from dynamically computed data key accesses.

If we require only private name objects on the right of @, then there's another benefit: no misspelled references to public name where a private one is required. @ means private, not computed.

Regardless of whether this proposal flies we could consider supporting:

private foo,bar;

as a short hand for:

//assume already done: import name as "@names"; const foo=name.create(), bar=name.create();

I think this would be a desirable addition, but I don't want it to be a make or break issue for the .@ proposal.

I'm game. Without it the Name.create() overhead is onerous.

There are a couple of decision that still need to make for this proposal:

  1. should .@ member access and @ object literal property definitions permit he property key to be any toString-able value and not just private name values? The current plan of record does not require a private name value in the analogous contexts. I'm slightly inclined towards requiring private name values, but would be happy either way.

As noted above, I'm inclined toward requiring private name objects on the right of @.

  1. elimination of arbitrary expression as direct keys in object literal property definitions:

The current "computed property keys" proposals allows things like:

for (var n=0;n<10;) { a.push( { ["prop"+n]: n++ }); }

Do we really need to support this sort of computed property name definition?

Not obviously at this point. We might want [] and @ but we can certainly defer [] if we do include @ for private names.

  1. should @foo as a primary expression be interpreted as this. at foo

I think it should, but note that this means that

const foo = name.create(); let obj = { @foo: @foo };

would mean the same as:

const foo = name.create(); let obj = { @foo: this. at foo /key and value probably different values };

rather than:

const foo = name.create(); let obj = { @foo: foo //key and value are the same value };

This might be a source of confusion for some JS programmers.

It's not different from let obj = {foo: foo} which uses foo two different ways. We agreed on the shorthand from object destructuring being necessary (due to the cover grammar technique we are using

# Brendan Eich (13 years ago)

Tab Atkins Jr. <mailto:jackalmage at gmail.com> January 22, 2012 7:36 PM myCoolObject.prototype[Iterator.getIterator] = function(){...} Using @ for access, would "myCoolObject.prototype. at Iterator.getIterator = function(){...}" work, or would that attempt to retrieve a property using "Iterator" as a Name, then retrieve the "getIterator" property of that?

To quote D. Duck, "pronoun trouble". By your final "that", you mean the iterator Name instance? If so, no way -- that doesn't make any sense. A dot operator in JS accesses a property value, not key.

So rest assured: the former.

# Tab Atkins Jr. (13 years ago)

On Sun, Jan 22, 2012 at 11:25 PM, Brendan Eich <brendan at mozilla.org> wrote:

Tab Atkins Jr. <mailto:jackalmage at gmail.com> January 22, 2012 7:36 PM

myCoolObject.prototype[Iterator.getIterator] = function(){...} Using @ for access, would "myCoolObject.prototype. at Iterator.getIterator = function(){...}" work, or would that attempt to retrieve a property using "Iterator" as a Name, then retrieve the "getIterator" property of that?

To quote D. Duck, "pronoun trouble". By your final "that", you mean the iterator Name instance? If so, no way -- that doesn't make any sense. A dot operator in JS accesses a property value, not key.

So rest assured: the former.

Allow me to be clearer.

Given "foo.bar = new Name();", is "baz. at foo.bar" equivalent to "baz[foo.bar]" or "baz[foo].bar"? Normal property-access semantics would give the latter. If so, then we need to preserve the [] form for use with private names in both the "baz[foo.bar]" form and the "{[foo.bar]: true}" form, unless we find it acceptable for authors to be forced to use a local variable to store the Name every time.

# Brendan Eich (13 years ago)

Tab Atkins Jr. <mailto:jackalmage at gmail.com> January 22, 2012 11:44 PM

Allow me to be clearer.

Given "foo.bar = new Name();", is "baz. at foo.bar" equivalent to "baz[foo.bar]" or "baz[foo].bar"?

There's no requirement that @ be lower precedence than a later dot. The abstract syntax is the same as (if parentheses were allowed)

baz.(@foo).bar

not

baz.(@foo.bar)

BTW, there's precedent for .@ in E4X (ECMA-357) and the grammar is the same, although the semantics are to access XML attributes:

js> x = <a b="c"/> <a b="c"/>

js> x. at b "c" js> x. at b.length()

1 js> x. at b.parent() <a b="c"/>

js> x. at b[0] "c" js> typeof x. at b[0] "xml" js> x. at b[0].nodeKind() "attribute"

Normal property-access semantics would give the latter.

Would give baz[foo].bar where foo = 'foo', you mean? Yes, that's true.

If so, then we need to preserve the [] form for use with private names in both the "baz[foo.bar]" form and the "{[foo.bar]: true}" form, unless we find it acceptable for authors to be forced to use a local variable to store the Name every time.

Let's split the cases:

  1. The baz[foo.bar] expression can be written in any event, whether foo.bar denotes a private name object or any other value (which is ToString'ed). There is no requirement to use a temporary to address such a private-named property -- [] works already and we aren't removing it.

Turning this around, just because . at foo works (no dot binding tighter than @) does not mean there's no alternative other than to use a temp if the private name is denoted foo.bar -- one can (currently, see closing below for more) use [].

  1. The {[foo.bar]: ...} object literal case is out of luck, but not because of @ binding tighter than dot -- we already do not support any kind of computed property name here. If we want one, we should consider [] syntax in the property name context in object literals.

Of course, we could elaborate @ to allow a parenthesized expression as its operand, so you could make the abstract syntax I sketched above concrete, with the ( after the @:

baz.@(foo.bar)

would obviously differ from

baz. at foo.bar

But this seems unnecessary in view of the existing [] operator (1 above).

The wrinkle here is future-proofing against

strawman:object_model_reformation

which has not yet achieved consensus in TC39. Once baz[foo.bar] might diverge from meaning property access, one could imagine needing baz.@(foo.bar). I'd rather cross that bridge if we come to it.

# Gavin Barraclough (13 years ago)

On Jan 22, 2012, at 10:29 PM, Brendan Eich wrote:

  1. should .@ member access and @ object literal property definitions permit he property key to be any toString-able value and not just private name values? The current plan of record does not require a private name value in the analogous contexts. I'm slightly inclined towards requiring private name values, but would be happy either way.

As noted above, I'm inclined toward requiring private name objects on the right of @.

It seems like an unfortunate inconvenience to require any code refactoring and lose the shorthand @ this-access if you just want to make a private property on an object be public. Instead of just restricting the token to the right of a @ or .@ construct be a private name, perhaps it would be useful to also permit an explicitly declared public name?

private x,y;
function point(x,y) {
	@x = x;
	@y = y;
}

can easily be transformed into:

public x,y;
function point(x,y) {
	@x = x;
	@y = y;
}

This would still provide a guard against typos, whilst giving convenient access to public properties on the this object.

# Axel Rauschmayer (13 years ago)

It seems like an unfortunate inconvenience to require any code refactoring and lose the shorthand @ this-access if you just want to make a private property on an object be public. Instead of just restricting the token to the right of a @ or .@ construct be a private name, perhaps it would be useful to also permit an explicitly declared public name?

I wouldn’t mix public and private, but it would be nice to have symmetry – only having a this shortcut for private names feels odd. How about the following?

function Point(everyone, secret) {
    this.everyone = everyone;
    this. at secret = secret;
}

//---- Short:

function Point(everyone, secret) {
    .everyone = everyone;
    . at secret = secret;
}

//---- Shorter:

function Point(this.everyone, this. at secret) {
}

//---- Shortest:

function Point(.everyone, . at secret) {
}

To me, consistency is much more important than saving characters.

# Brendan Eich (13 years ago)

Axel Rauschmayer <mailto:axel at rauschma.de> January 23, 2012 1:21 AM

I wouldn’t mix public and private, but it would be nice to have symmetry – only having a this shortcut for private names feels odd. How about the following?

function Point(everyone, secret) { this.everyone = everyone; this. at secret = secret; }

//---- Short:

function Point(everyone, secret) { .everyone = everyone;

You're requiring manual semicolon insertion before lines like this. Consciously?

# Axel Rauschmayer (13 years ago)

function Point(everyone, secret) { .everyone = everyone;

You're requiring manual semicolon insertion before lines like this. Consciously?

Sight. Right. Not a good idea, then.

An important consideration is that eliminating this will increase the grawlix-factor of JavaScript (I always liked the explicit this, especially compared to Java).

# François REMY (13 years ago)

Just to confirm: you are not alone. I always thought that allowing to imply local this (‘this.’) was a bad idea (C#). Seriously, this is not 5 chars that’ll hurt but it could make IDE work a lot easier, and it make code reuse more efficient (if you need to copy/paste some code, if you stay in the same class, it will work as intended, not if a function argument can override the class field). It also brings symetry to the code (this.a==other.a). From: Axel Rauschmayer Sent: Monday, January 23, 2012 10:26 AM To: Brendan Eich Cc: ECMAScript discussion Subject: Re: shortcuts for defining block-local private names,plays nicely with @foo syntax

function Point(everyone, secret) {

  .everyone = everyone;

You're requiring manual semicolon insertion before lines like this. Consciously?

Sight. Right. Not a good idea, then.

An important consideration is that eliminating this will increase the grawlix-factor of JavaScript (I always liked the explicit this, especially compared to Java).

# Axel Rauschmayer (13 years ago)

Note: JavaScript will never go the Java or C# route of including properties in local scope (which would be just like with), there will just be a shortcut for this (so IDEs won’t have a problem).

But I agree with your other points: my taste is such that 5 chars are not worth the increase in grawlixiness and I enjoy the symmetry induced by the longer this.

# Andreas Rossberg (13 years ago)

On 23 January 2012 01:31, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:

  1. elimination of arbitrary expression as direct keys in object literal property definitions:

The current "computed property keys" proposals allows things like:

for (var n=0;n<10;) {    a.push( {       ["prop"+n]: n++    }); }

Do we really need to support this sort of computed property name definition?

If we are going for the customizability of [] that you were proposing, then, yes, I think this form of literal still makes a lot of sense, as a way to write custom collection literals. E.g.

let m = Map <| { [1]: a, [2]: b }

It would simply expand to respective assignments.

If so, we could probably allow something such as:

for (var n=0;n<10;) {    a.push( {      @("prop"+n): n++    }); }

Not sure about this particular example, but I reckon that you might want to write something like

@(M.a)

where M' is a module that exports a private namea'. This applies to dot notation as well as object literals:

let o = { @(M.a): 4 } o.@(M.a)

  1. should @foo as a primary expression be interpreted as this. at foo

That seems irregular and confusing indeed.

# Herby Vojčík (13 years ago)

Allen Wirfs-Brock wrote:

The plan of record is that ES6 will support the creation of private named properties in object literals using syntax like this:

const foo = name.create(); let obj = { [foo]: 42 };

However, if @foo is going to be used for private named member accesses instead of [foo] then it also makes sense to use @ instead of [ ] in object literal property definitions. In that case, we should replace the above with:

const foo = name.create(); let obj = { @foo: 42 };

Note that this doesn't run into any of the scoping or multiple name space issues that were raised as objections to the original private name proposals liked above. Also it doesn't preclude use of [ ] to access private names. You could still say either obj[foo] or obj. at foo to access the properties whose key is the value of foo

I plan on proposing at the next TC39 meeting that we support .@ member accesses and that we replace the use of [expr ] to define private named properties in object literals ( harmony:object_literals#object_literal_computed_property_keys ) with @identifier to define such properties.

+1 for adding @foo:x to literals. Not needing to remove [expr]:x, though.

Regardless of whether this proposal flies we could consider supporting:

private foo,bar;

as a short hand for:

//assume already done: import name as "@names"; const foo=name.create(), bar=name.create();

I will repeat myself here, but I would like the 'private foo, bar' to have different semantics; that is to be shorthand for something else.

In this code:

module { export function factory1 (args) { return { @foo: ..., ..., f(other) { return Math.max(@foo, other. at foo); } }; }

 export function factory2 (args) {
   return { @bar: ..., leq(other) { return @bar < other. at bar; } }
 }

 ...

 // different piece of code copied from web example
 // using its unrelated @bar

}

The idea here is, product of factory1 and factory2 must play nicely with their siblings. So if this would not work:

 export function factory1 (args) {
   private foo;
   return { ...

nor similar for factory2. I'd say majority of Name uses are of this kind: so it be the same name in subsequent invocations of the block.

It can be solved this way:

module { private foo, bar;

 export function factory1 (args) { ... }

 export function factory2 (args) { ... }

but then foo and bar are known to the rest of the module. It was not the premise. It now clashes with:

 // different piece of code copied from web example
 // using its unrelated @bar

and even if did not, it is bad idea to "globally" define something just for local use of little part of code. So, to do this right, one probably needs to:

module { { private foo; export function factory1 (args) { return { @foo: ..., ..., f(other) { return Math.max(@foo, other. at foo); } }; } }

 {
   private bar;
   export function factory2 (args) {
     return { @bar: ..., leq(other) { return @bar < other. at bar; } }
   }
 }
 ...

 // different piece of code copied from web example
 // using its unrelated @bar

}

and that's gross :-/.

So, please, consider the possibility, that

private foo

will not be shortcut for plain and simply writable:

const foo = Name.create();

but for more complicated

lexical_singleton foo = Name.create();

so that previous code could be written:

module { export function factory1 (args) { private foo; return { @foo: ..., ..., f(other) { return Math.max(@foo, other. at foo); } }; }

 export function factory2 (args) {
   private bar;
   return { @bar: ..., leq(other) { return @bar < other. at bar; } }
 }

 ...

 // different piece of code copied from web example
 // using its unrelated @bar

}

without need to simulate lexically local variable with runtime wrapping.

I think this would be a desirable addition, but I don't want it to be a make or break issue for the .@ proposal.

Yes.

There are a couple of decision that still need to make for this proposal:

  1. should .@ member access and @ object literal property definitions permit he property key to be any toString-able value and not just private name values? The current plan of record does not require a private name value in the analogous contexts. I'm slightly inclined towards requiring private name values, but would be happy either way.

Names only. Saves lot of complication below. Makes intent clear.

  1. elimination of arbitrary expression as direct keys in object literal property definitions:

The current "computed property keys" proposals allows things like:

for (var n=0;n<10;) { a.push( { ["prop"+n]: n++ }); }

Do we really need to support this sort of computed property name definition? If so, we could probably allow something such as:

It is powerful. Could help a lot in certain situation. I would vote for not putting it away.

for (var n=0;n<10;) { a.push( { @("prop"+n): n++ }); }

I'm include to not supporting the such arbitrary expressions in such property definitions, particularly if 1) above is decided as no. Then

Definitely.

  1. should @foo as a primary expression be interpreted as this. at foo

I think it should, but note that this means that

... a couple of examples ...

This might be a source of confusion for some JS programmers.

Only for a while. I am for this. at foo. Helps much more than it sometimes confuses.

# Axel Rauschmayer (13 years ago)

On Jan 23, 2012, at 12:21 , Herby Vojčík wrote:

Allen Wirfs-Brock wrote:

I plan on proposing at the next TC39 meeting that we support .@ member accesses and that we replace the use of [expr ] to define private named properties in object literals ( harmony:object_literals#object_literal_computed_property_keys ) with @identifier to define such properties.

+1 for adding @foo:x to literals. Not needing to remove [expr]:x, though.

Hopefully, [] will become a full application data domain construct [1][2] (and exclusively so). Then it makes no sense in object literals.

However, @ could completely take over the program definition domain role of []:

  1. Allow @ for both strings and name objects
  2. Use @(expr) for property access via a computed name

However, with built-in maps, I’m not sure how frequent the use cases for #1 and #2 will be. Object.getProperty(key) might be enough.

[1] strawman:object_model_reformation [2] www.2ality.com/2012/01/roles-objects-arrays.html

# Brendan Eich (13 years ago)

Herby Vojčík <mailto:herby at mailbox.sk> January 23, 2012 3:21 AM It can be solved this way:

module { private foo, bar;

export function factory1 (args) { ... }

export function factory2 (args) { ... }

but then foo and bar are known to the rest of the module. It was not the premise.

There is nothing wrong with this solution, and everything right. If you want to keep foo and bar secret from other modules, you've done so. If you, for some reason, want to keep them secret from other contents of this module, use a block (but you'll have a harder time exporting

# Allen Wirfs-Brock (13 years ago)

On Jan 22, 2012, at 7:36 PM, Tab Atkins Jr. wrote:

... I have a question, that may be an objection. In my blog post www.xanthir.com/blog/b4FJ0, I demonstrate several example usages of Names. Most of them involve using a Name that's hung off of another object. Is there a way to support this pattern without a temporary variable?

I agree, this is another common use case that I should have mentioned in my message.

An alternative to handing such private names off of object is to export them as const bindings from a module. You can see an example of this style in strawman:object_model_reformation#a_string_keyed_map

For example, from my post:

myCoolObject.prototype[Iterator.getIterator] = function(){...}

Using @ for access, would "myCoolObject.prototype. at Iterator.getIterator = function(){...}" work, or would that attempt to retrieve a property using "Iterator" as a Name, then retrieve the "getIterator" property of that?

If the latter, this is rather inconvenient for what I expect will be common patterns.

myCoolObject.prototype. at Iterator.getIterator

parses as: ((myCoolObject.prototype). at Iterator).getIterator

which probably is not what you desire.

Taking just what is in my basic proposal, you would have to express this using a local variable:

const getIterator = Iterator.getIterator; myCoolObject.prototype. at getIterator = function() {...}

If @( ) is allowed for property keys in object literals you could say:

obj = { @(Iterator.getIterator): function () {...} }

or using concise method syntax just

obj = { @(Iterator.getIterator) () {...} }

however if we want to directly use Iterator.getIterator as the key in a member expression we would need to enable use of @() as the property name in a member expression:

myCoolObject.prototype.@(Iterator.getIterator) = function () {...}

I'm still ambivalent whether we actually need this. I think I like the module export pattern slightly better and might prefer to encourage that.

Another possible extension would be to allow private declarations of the form:

private getIterator = Iterator.getIterator;

this really would mean exactly the same as an equivalent with const (perhaps the initializer might be throw if it doesn't evaluate to a private name) but it emphasizes the intended usage.

# Brendan Eich (13 years ago)

Allen Wirfs-Brock <mailto:allen at wirfs-brock.com> January 23, 2012 8:43 AM On Jan 22, 2012, at 7:36 PM, Tab Atkins Jr. wrote:

For example, from my post:

myCoolObject.prototype[Iterator.getIterator] = function(){...}

Using @ for access, would "myCoolObject.prototype. at Iterator.getIterator = function(){...}" work, or would that attempt to retrieve a property using "Iterator" as a Name, then retrieve the "getIterator" property of that?

If the latter, this is rather inconvenient for what I expect will be common patterns.

myCoolObject.prototype. at Iterator.getIterator

parses as: ((myCoolObject.prototype). at Iterator).getIterator

which probably is not what you desire.

Taking just what is in my basic proposal, you would have to express this using a local variable:

const getIterator = Iterator.getIterator; myCoolObject.prototype. at getIterator = function() {...}

Why wouldn't myCoolObject.prototype[iterator.getIterator] work?

# Allen Wirfs-Brock (13 years ago)

Below...Brendan Eich <brendan at mozilla.org> wrote:> Allen Wirfs-Brock <mailto:allen at wirfs-brock.com>

January 23, 2012 8:43 AM On Jan 22, 2012, at 7:36 PM, Tab Atkins Jr. wrote:

?..

const getIterator = Iterator.getIterator; myCoolObject.prototype. at getIterator = function() {...}

Why wouldn't myCoolObject.prototype[iterator.getIterator] work?

/be

It would, for now.  But, I think you gave the reason for avoiding this pattern in another reply. If we ever want to adopt my Reformed Object Model proposal then we should avoid using [ ] for private name property access.  lt would actually still work fine for objects with default [ ] behavior but not for collection objects that redefine [ ] access.

Before encouraging a new pattern like obj[Iterator.GetIterator] we should think about its future-proofing implicationa.

# Brendan Eich (13 years ago)

Allen Wirfs-Brock <mailto:allen at wirfs-brock.com> January 23, 2012 11:01 AM

Below... Brendan Eich <brendan at mozilla.org> wrote:

Allen Wirfs-Brock <mailto:allen at wirfs-brock.com> January 23, 2012 8:43 AM On Jan 22, 2012, at 7:36 PM, Tab Atkins Jr. wrote:

?..

const getIterator = Iterator.getIterator; myCoolObject.prototype. at getIterator = function() {...}

Why wouldn't myCoolObject.prototype[iterator.getIterator] work?

/be

It would, for now. But, I think you gave the reason for avoiding this pattern in another reply. If we ever want to adopt my Reformed Object Model proposal then we should avoid using [ ] for private name property access. lt would actually still work fine for objects with default [ ] behavior but not for collection objects that redefine [ ] access.

Before encouraging a new pattern like obj[Iterator.GetIterator] we should think about its future-proofing implicationa.

We run into this kind of trade-off all the time, but the fact is that right now, dot and brackets are equivalent for properties named by strings that match the IdentifierName lexical production. This isn't the case for private names, of course -- by design: no string equivalent so no dot.

However it does not follow that a first-class private name object value cannot be used in square brackets to access a property it names. If we must future-proof, then it follows that .@ and even .@() must be part of private name objects. If everyone agrees, then we have a decision to make.

# Brendan Eich (13 years ago)

Brendan Eich <mailto:brendan at mozilla.org> January 23, 2012 11:08 AM

We run into this kind of trade-off all the time, but the fact is that right now, dot and brackets are equivalent for properties named by strings that match the IdentifierName lexical production. This isn't the case for private names, of course -- by design: no string equivalent so no dot.

This was prolog, but then I edited too much and may have been unclear:

However it does not follow that a first-class private name object value cannot be used in square brackets to access a property it names.

This is about harmony:private_name_objects

# Herby Vojčík (13 years ago)

Brendan Eich-2 wrote:

# Brendan Eich (13 years ago)

Herby Vojčík <mailto:herby at mailbox.sk> January 23, 2012 11:51 AM Brendan Eich-2 wrote:

Herby Vojčík<mailto:herby at mailbox.sk> January 23, 2012 3:21 AM It can be solved this way:

module { private foo, bar;

 export function factory1 (args) { ... }

 export function factory2 (args) { ... }

but then foo and bar are known to the rest of the module. It was not the premise. There is nothing wrong with this solution, and everything right. If you want to keep foo and bar secret from other modules, you've done so. If you, for some reason, want to keep them secret from other contents of this module, use a block (but you'll have a harder time exporting -- export must come at module top level).

In other way, it is impossible to have truly lexical-local private names.

No, the private binding form that is desugared from

private foo;

to

const foo = Name.create("foo");

or better (with hygiene to use the right Name, etc.) is lexical in its binding structure.

You must define them all at the upper level, tens or maybe hundreds of lines back.

What?

We're talking about singletons -- you seemed to agree. Why should deeply nested declarations be evaluated only once (at compile time? What does that mean exactly? Or somehow first-run-only, at their nesting depth...)?

There's no difference here between other forms, including regular expression literals and function expressions and declarations. A function declaration in particular is evaluated ot a fresh object bound to the declared name. The desugaring is complicated by hoisting, but consider a magic hoist primitive:

function bar(params) {body}

desugars to

hoist bar = function bar(params) {body};

and you get a fresh object per evaluation.

You want to mislocate private for some reason. Why? Are you focused too much on class constructors?

The module with two functions sharing private names use-case is addressed by module-scope private declarations. What is the syntax you want there?

# Gavin Barraclough (13 years ago)

On Jan 23, 2012, at 12:27 PM, Brendan Eich wrote:

No, the private binding form that is desugared from

private foo;

to

const foo = Name.create("foo");

or better (with hygiene to use the right Name, etc.) is lexical in its binding structure.

Is the intention here that the private name object would be in scope, and accessible to the user? – if so, this does seem useful, but using the plain name of the property seems potentially prone to typos, e.g.

let o = {}; { private x: o.setX = function(x) { @x = x; } o.getX = function() { return x; // should be 'return @x;' } }

I seems that this would be an easy mistake to make, and doesn't appear to be a syntax error is x is in scope. Wanting to pass around the private name seems like a less common use case, so perhaps it might be worth making it slightly harder to get to the private name?, e.g.

const @@foo = Name.create("foo"); const @{foo} = Name.create("foo"); const @"foo" = Name.create("foo");

function getPrivateName() { return @@foo; } function getPrivateName() { return @{foo}; } function getPrivateName() { return @"foo"; }

# Herby Vojčík (13 years ago)

Brendan Eich wrote:

Herby Vojčík <mailto:herby at mailbox.sk> January 23, 2012 11:51 AM Brendan Eich-2 wrote:

Herby Vojčík<mailto:herby at mailbox.sk> January 23, 2012 3:21 AM module { private foo, bar;

export function factory1 (args) { ... }

export function factory2 (args) { ... }

but then foo and bar are known to the rest of the module. It was not the premise. There is nothing wrong with this solution, and everything right. If you want to keep foo and bar secret from other modules, you've done so. If you, for some reason, want to keep them secret from other contents of this module, use a block (but you'll have a harder time exporting -- export must come at module top level).

In other way, it is impossible to have truly lexical-local private names.

No, the private binding form that is desugared from

private foo;

to

const foo = Name.create("foo");

or better (with hygiene to use the right Name, etc.) is lexical in its binding structure.

Ok, let me be as exact as possible. I've got caught on imperfect formulation often. It is impossible to have lexically-local runtime-shared-over-the-subsequent-invocations private name.

You must define them all at the upper level, tens or maybe hundreds of lines back.

What?

We're talking about singletons -- you seemed to agree. Why should deeply nested declarations be evaluated only once (at compile time? What does that mean exactly?

That means exactly: "Here I want to use foo as a private identifier, known only to me." And of course, since it is a (private) identifier, it should be identical in all invocations, in other words, shared between invocations.

that mean exactly? Or somehow first-run-only, at their nesting depth...)?

Since all I want to do is to "have a private identifier to use", I do not actually run anything, in a typical sense. If you look at it nogt through imperative desugaring (forget it for a while), but as an aliasing (of a singleton hoisted up automatically), there is no need to be afraid of "Why should deeply nested declarations be evaluated only once" or "somehow first-run-only". I am not talking about generic mechanism of static a la C expressions stored in singletons.

I am only talking about pre-generated private names (deeply-frozen immutable objects) and aliasing them deep down.

They are like identifiers (private names really have this nature, when paired with @). Or they are like string constants. They are also created once in compile-time (or it seems so, implementation details aside) and nobody seems to be bothered.

There's no difference here between other forms, including regular expression literals and function expressions and declarations. A function declaration in particular is evaluated ot a fresh object bound to the declared name. The desugaring is complicated by hoisting, but consider a magic hoist primitive:

function bar(params) {body}

desugars to

hoist bar = function bar(params) {body};

and you get a fresh object per evaluation.

True. You probably want to bring an analogy that function declared within block is always different in each invocation, that is, hoisting is only inside innermost function/module/program scope...

You want to mislocate private for some reason. Why? Are you focused too much on class constructors?

... but as I already hinted, I see a difference in purpose between things like function and the private name. That is why I want to "mislocate" it.

Function is "living" object, having input, processing and output. I see private name as a "dead" thing, akin to identifier. The identifier defined deep down is lexically-local, but it is always the same identifier in every invocation.

I can show an analogy on this: You access foo.bar, and you access foo. at baz in the same block. In all invocations, foo.bar is always foo["bar"], "bar" is always the same constant (foo may be different). It is very probable, that you have the same purpose there for foo. at baz, the only difference being public/private, that is, so that foo. at baz is always foo[_the_shared_baz_private_name].

I have written in my first post, that there definitely are other uses of private names, where you want them used more dynamically (there are also many uses of public name, where you want then used more dynamically, and you use foo[dynamic_expression] for that). But there are more of plain foo.bar there. That is why I say there is more of foo. at the_shared_lexically_local_bar.

You need not to declare identifiers. You simply write them and you have them. But it is not do for private names playing the identifier role. For them, the 'private foo' as a means of declaration 'foo will be used here as a private name playing role of identifier, that is, being the same in all invocations' was devised.

(and yes, classes are typical use case. But it is not special for classes in 'class keyword' but in broader term - anywhere when things with similar structure are cooperating)

The module with two functions sharing private names use-case is addressed by module-scope private declarations. What is the syntax you

Not if they are deep down, included in, for example, class and inside that, included as local functions inside a method (for example). There, the name local only to the innermost lexical scope would be much better. For the locality is good thing. You can easily move such code (with locally defined private names) anywhere and it will simply work.

By saying: if you want shared private identifier, you must create it at runtime, so you must define it at the (module|program), you are breaking locality and forcing relation of things that are apart. Not nice, will lead to bugs.

want there?

/be

I hope at least now I was understood better.

# Brendan Eich (13 years ago)

Gavin Barraclough <mailto:barraclough at apple.com> January 23, 2012 12:54 PM On Jan 23, 2012, at 12:27 PM, Brendan Eich wrote:

Is the intention here that the private name object would be in scope, and accessible to the user? – if so, this does seem useful, but using the plain name of the property seems potentially prone to typos, e.g.

let o = {}; { private x: o.setX = function(x) { @x = x; } o.getX = function() { return x; // should be 'return @x;' } }

I seems that this would be an easy mistake to make, and doesn't appear to be a syntax error is x is in scope.

Yes, so the above would need to use px or some such obfuscated name for the private binding.

Previously we had private x; bind in a separate lexical chain from the one searched for identifiers to right of . and before : in object literals. That foundered on readability (which x?).

Then I think we considered a proposal where private x; bound in a separate lexical chain but that chain was searched only on right of @. That proposal seemed not to have the readability drawback. It also solves the problem you show above?

But now we've jumped to same single lexical chain. Did we skip a useful alternative design?

# Gavin Barraclough (13 years ago)

On Jan 23, 2012, at 1:11 PM, Brendan Eich wrote:

Then I think we considered a proposal where private x; bound in a separate lexical chain but that chain was searched only on right of @. That proposal seemed not to have the readability drawback. It also solves the problem you show above?

Ah, that's the detail that I'd missed! - if private names will be ignored if they are not to the right of @, then presumably my example would result in at least a reference error, since 'x' would not in scope in 'getX' (unless of course x resolves to the global object...). I was wrong in thinking that getX would return the private name? – if so, this sounds good to me!

Do we want there to be a way to be able to get to a private name object declared by 'private foo;' syntax, or if developers want to get their hands on a private name objects that they can pass around should they just be calling Name.create directly?

# Brendan Eich (13 years ago)

Gavin Barraclough <mailto:barraclough at apple.com> January 23, 2012 1:22 PM On Jan 23, 2012, at 1:11 PM, Brendan Eich wrote:

Ah, that's the detail that I'd missed! - if private names will be ignored if they are not to the right of @, then presumably my example would result in at least a reference error, since 'x' would not in scope in 'getX' (unless of course x resolves to the global object...).

Wait, your example was:

{ private x: o.setX = function(x) { @x = x; } o.getX = function() { return x; // should be 'return @x;' } }

You have private x in the private @-scope chain of both of those function expressions.

I was wrong in thinking that getX would return the private name? – if so, this sounds good to me!

You were wrong in the middle alternative I think we skipped too quickly -- that x is unbound. We'd need a way to reflect from @-scope into value expression domain. The old private names proposal used #. as a prefix.

Do we want there to be a way to be able to get to a private name object declared by 'private foo;' syntax, or if developers want to get their hands on a private name objects that they can pass around should they just be calling Name.create directly?

I see no problem with an explicit reflection operator, so e.g. getX could say return @x or @(x) -- assuming we don't that syntax for something else. Perhaps there is better syntax, but the point is we can make this require an explicit operation.

# Allen Wirfs-Brock (13 years ago)

I think I'm largely in agreement with what you were saying below, but I do have some additional thoughts I added below...

On Jan 23, 2012, at 11:28 AM, Brendan Eich wrote:

Brendan Eich <mailto:brendan at mozilla.org> January 23, 2012 11:08 AM

We run into this kind of trade-off all the time, but the fact is that right now, dot and brackets are equivalent for properties named by strings that match the IdentifierName lexical production. This isn't the case for private names, of course -- by design: no string equivalent so no dot.

This was prolog, but then I edited too much and may have been unclear:

However it does not follow that a first-class private name object value cannot be used in square brackets to access a property it names.

This is about harmony:private_name_objects -- an accepted proposal in Harmony and extremely likely to be going into ES6.

And nothing that I'm currently proposing would take away the ability to use a private name value with square brackets to access properties. However, the current private names object proposal exclusively relies on the use of square brackets. My contention is that there are both usability/readability and future-proofing reasons to provide a different preferred mechanism such as .@ as the primarily way of accessing private name keyed properties instead of requiring use of the obj[privateNameValue] pattern.

Also, the square bracket preference also currently shows up in the object literal computed property key proposal so we already have obj[privateNameValue] pattern manifesting itself as new ES6 syntax.

If we must future-proof, then it follows that .@ and even .@() must be part of private name objects. If everyone agrees, then we have a decision to make.

Yes, that is exactly my position.

I don't think everyone agrees on future-proofing for

strawman:object_model_reformation

Well from my reading, there seems to be at least as much support for Object Model Reformation on this list as there is for guards and we seem to put considerable attention into future proofing for guards. I think extensions to property access including support for private names is an area where we need to think carefully about future implications.

yet, so I wonder if we'll all agree to add.@ etc. to private_name_objects. That got into Harmony by avoiding new syntax. We do not want to go in a circle here (rather, a progress-making spiral ;-).

I agree, having no syntax helped to get agreement on private_name_objects. But now that people are experimenting with coding patterns using them we are beginning to see the usability and future-proofing problems of exclusively depending upon [ ] access. There may now be a better understanding of how private name objects usage could benefit from some syntactic affordances. Spiraling out from private name objects to include .@ and {@name:etc} seems like an all around win that I would hope we could accomplish without just circling around private names again. It is less clear whether we need .@() or the private declaration but the seem worthwhile to consider has part of the whole private name package.

# Axel Rauschmayer (13 years ago)

Also, the square bracket preference also currently shows up in the object literal computed property key proposal so we already have obj[privateNameValue] pattern manifesting itself as new ES6 syntax.

Would [] in object literals still make sense if [] was to become a data-only operator?

# Allen Wirfs-Brock (13 years ago)

On Jan 23, 2012, at 7:43 PM, Axel Rauschmayer wrote:

Also, the square bracket preference also currently shows up in the object literal computed property key proposal so we already have obj[privateNameValue] pattern manifesting itself as new ES6 syntax.

Would [] in object literals still make sense if [] was to become a data-only operator?

Perhaps, but not with its current proposed meaning. Assume you have already defined a prototypal object Dictionary, then it might be useful to create literal instance of it by saying something like:

let myDict = Dictionary <| { ["key1"]: 1, [computedKey()]: 2, [var]: 3 };

For that to work, the individual element definitions would have to desugar into @elementSet method calls on the new object and Dictionary would presumably have defined @elementSet.

This might be combined with regular property definitions, for example:

let myDict = Dictionary <| { ["key1"]: 1, [computedKey()]: 2, [var]: 3, initialLength: 3 };

However, things would break down if you wanted to add a private named property using the current obj lit computed property name proposal:

const myTradeMark = name.create(); let myDict = Dictionary <| { ["key1"]: 1, [computedKey()]: 2, [var]: 3, initialLength: 3, [myTradeMark]: true };

As [myTradeMark]: true would create a dictionary element instead of a property. To get around this we would need a different way to define private named properties in object literals, such as:

const myTradeMark = name.create(); let myDict = Dictionary <| { ["key1"]: 1, [computedKey()]: 2, [var]: 3, initialLength: 3, @myTradeMark: true };

I'm not convinced that this style of literal is actually that practical considering that many collection abstractions would need to initialize their instances before inserting elements and it isn't clear how that initialization would occur for such literals.

Regardless, if we want to ever have a reformed object model where [ ] can be defined to mean element access we probably shouldn't also depend upon [ ] for private named property definition considering that any object that redefines [ ] is going to have to define and probably invoke the private named elementGet/elementSet methods. Consider the strawman:object_model_reformation#a_string_keyed_map example. If @. wasn't available to use to reference private named properties something like explicit Object.getProperty calls would have to be used instead and it would look like:

module Name from "@name"; import {elementGet, elementSet, elementDelete} from Name; import iterator from "@iter";

const backingStore = Name.create(); export function StringKeyedMap() { Object.setProperty(this,backingStore) = Object.create(null); //note @backingStore object is a "normal object" and [ ] on it does regular property access } Object.setProperty(StringKeyedMap.prototype,elementGet) = function(k) {return Object.getProperty(this,backingStore)[k]} Object.setProperty(StringKeyedMap.prototype,elementSet) = function(k,v) {Object.getProperty(this,backingStore)[k]=v;} StringKeyedMap.prototype.size = function() {Object.getOwnPropertyNames(Object.getProperty(this,backingStore).length}; //I'm lazy StringKeyedMap.prototype.has = function(k) {return {}.hasOwnProperty.call(Object.getProperty(this,backingStore),k}; Object.setProperty(StringKeyedMap.prototype,elementDelete) = function(k) {return delete Object.getProperty(this,backingStore)[k]} Object.setProperty(StringKeyedMap.prototype,iterator) = function() { // iteration yields key/value pairs let self = this; let backing = Object.getProperty(this,backingStore); return (function*() {for (let x in backing) {if (self.has(x)) yield [x, backing[x]]}})(); }

Much less pleasant than the original example using @.

# Axel Rauschmayer (13 years ago)

Reiterating my support for the reformed object model (ROM): I love how the ROM will finally end the clashes between application data (array elements, entries in objects-as-maps) and program definition (methods, non-method properties). It’s a nice clean-up, with a clear migration strategy.

Regardless, if we want to ever have a reformed object model where [ ] can be defined to mean element access we probably shouldn't also depend upon [ ] for private named property definition considering that any object that redefines [ ] is going to have to define and probably invoke the private named elementGet/elementSet methods.

@() could take the place of [] for property access, if we allow string operands.

# Brendan Eich (13 years ago)

Axel Rauschmayer <mailto:axel at rauschma.de> January 24, 2012 11:06 AM Reiterating my support for the reformed object model (ROM): I love how the ROM will finally end the clashes between application data (array elements, entries in objects-as-maps) and program definition (methods, non-method properties). It’s a nice clean-up, with a clear migration strategy.

@() could take the place of [] for property access, if we allow string operands.

You realize this is a huge change that will break a lot of code, if done incompatibly. If you "do both" (only certain collections misbehave when using [] to access properties rather than collection data), you'll still have breakage -- and confusion.

I'm not saying we can't do OMR or whatever it ought to be called. But we should not require ocean-boiling, or make a "big red switch" problem.

# Axel Rauschmayer (13 years ago)

Reiterating my support for the reformed object model (ROM): I love how the ROM will finally end the clashes between application data (array elements, entries in objects-as-maps) and program definition (methods, non-method properties). It’s a nice clean-up, with a clear migration strategy.

@() could take the place of [] for property access, if we allow string operands.

You realize this is a huge change that will break a lot of code, if done incompatibly. If you "do both" (only certain collections misbehave when using [] to access properties rather than collection data), you'll still have breakage -- and confusion.

I'm not saying we can't do OMR or whatever it ought to be called. But we should not require ocean-boiling, or make a "big red switch" problem.

I’d leave Object and Array as is and introduce two collection types:

  1. List (or Sequence or something else): same interface as Array (hence array-like). No holes, indices are non-negative integers, etc.
  2. Map (possibly the SimpleMap that has already been specified).

Both types would be recommended replacements (especially Map for Object-as-map) and separate elements/entries from properties (with obvious benefits – no shadowing, less tricky key enumeration).

Would that boil oceans?

  • With OMR, swapping Arrays for Lists would be trivial, because you could keep using [] for element access.
  • I’m not sure that arrays need to be replaced, but objects as maps are so difficult to handle that using something else is a must, IMHO.
# Allen Wirfs-Brock (13 years ago)

On Jan 24, 2012, at 12:35 PM, Axel Rauschmayer wrote:

Reiterating my support for the reformed object model (ROM): I love how the ROM will finally end the clashes between application data (array elements, entries in objects-as-maps) and program definition (methods, non-method properties). It’s a nice clean-up, with a clear migration strategy.

@() could take the place of [] for property access, if we allow string operands.

You realize this is a huge change that will break a lot of code, if done incompatibly. If you "do both" (only certain collections misbehave when using [] to access properties rather than collection data), you'll still have breakage -- and confusion.

I'm not saying we can't do OMR or whatever it ought to be called. But we should not require ocean-boiling, or make a "big red switch" problem.

This is all pretty much covered in the Object Model Reformation strawman proposal. Nothing in that proposal would change the behavior of any existing code. What it does provide is the opportunity for ES programmer to define new object abstractions where [ ] means something different from normal property access. This is an opportunity that is already available and used by some built-in and host object (particularly the DOM) authors. The distinction between data element ([ ]) and property access would only exist for objects that explicitly define the differences.

However, an implication permitting the redefintion of [ ] on a per object basis is that obj.foo and obj['foo'] are not always the same operation. Whether that identify holds depends upon the definition of obj. This is why the proposal was titled "Object Model Reformation" -- it requires ES programmers (over time) to start thinking of [ ] and property access as distinct operations that are not necessarily coupled to each other. If we think there is a possibility that of moving in that direction then we should avoid introducing new idioms, such as using [ ] for private property access, that would be problematic for objects that decouple [ ] and property access.

I’d leave Object and Array as is and introduce two collection types:

We must leave Object and Array as is. However, it would be possible to reimplement the existing Array semantics in ES without needing to use Proxies: strawman:object_model_reformation#implementing_built-in_array_semantics_without_using_proxy

  1. List (or Sequence or something else): same interface as Array (hence array-like). No holes, indices are non-negative integers, etc.
  2. Map (possibly the SimpleMap that has already been specified).

One reason I introduced this the OMR strawman when I did is because we are already committed to adding new "collection" objects (Map, WeakMap, Set, and possibly others) to ES6 and that they currently have to use get/set method-based APIs. Early adoption of OMR would allow these new kinds of collections to use [ ] for data element access. I also suspect (but haven't worked through the details) that use of OMR could also improve inthe Binary Data/Typed Array abstractions.

# Axel Rauschmayer (13 years ago)
  1. List (or Sequence or something else): same interface as Array (hence array-like). No holes, indices are non-negative integers, etc.
  2. Map (possibly the SimpleMap that has already been specified).

One reason I introduced this the OMR strawman when I did is because we are already committed to adding new "collection" objects (Map, WeakMap, Set, and possibly others) to ES6 and that they currently have to use get/set method-based APIs. Early adoption of OMR would allow these new kinds of collections to use [ ] for data element access. I also suspect (but haven't worked through the details) that use of OMR could also improve inthe Binary Data/Typed Array abstractions.

Different implementations would also allow one to optimize for either of the two use cases of arrays: Lisp-style linked lists versus Java-style fixed-size contiguous arrays with efficient random access.

Not sure how to express that decision in code, possibly via an aliases to a constructors (a.k.a poor man’s typedef).

 const ListArray = LinkedList;
 const VectorArray = FixedSizeContiguousArray;
 // problem: Array can’t be a RHS above, Array.of() might work

I would also want a method such as Array.isArrayLike(), but that might be jumping the gun and best delayed until there are contracts or something similar.

# Herby Vojčík (13 years ago)

(resend to list; forgot)

Sorry for late answer, but I lost mails from Monday 4:30-17:30 CET, so I waited for them to appear in .gz archive to download and import them to mu inbox again.

Answers below.

Brendan Eich wrote:

Herby Voj??k<mailto:herby at mailbox.sk> January 22, 2012 12:34 PM Brendan Eich wrote:

I suspect your very complicated translation with prvTable etc. is intended to hoist private somehow, once per declaration in source rather than once per evaluation of declaration. That's too restrictive, since Exactly. By design.

For classes, we have agreed on class-private, rather than instance-private, instance variables. However you don't need such a

Of course, classes were the primary concern in that proposal of mine. But I hate special cases. Since it seems you really want private foo to be shortcut for const foo = Name.create(), I can go with it ...

complex desugaring for classes, and "private x;" not in a class should be evaluated, not hoisted into singleton-hood somehow.

class Point { ... private x, y; ... } // ignore details of whether in constructor or class body

should desugar roughly to

let Point = do { private x, y; class Point { ... ... } };

... by generalizing it* so that:

  • if private foo appears in code, it is shortcut for const foo = Name.create()
  • if private appears in object literal, it is desugared to [assignment = ] do { private foo; expression_using_a_literal; }
  • I am treating class block as an object literal. I will always try to make it so that class is in fact an operator on object literal. I am not good with explaining why it is good, though I am trying. I see real (future-friendly) reason for not having any kind of special block for class.

so as to achieve the class-private instance variable semantics wanted.

If the class is created as a class expression inside some function or method, the private name is always different. Yes, the class is also always different. May lead to little confusion, but nothing critical. Maybe it is good to raise awareness to this case somewhere.

This does suggest that putting the private declarations in constructor is a mistake, since they would seem to be generated once per construction (instance), not once per class (as class-private wants).

Yes.