On Jul 8, 2011, at 12:16 PM, Allen Wirfs-Brock wrote:

> The current Harmony classes proposal 
> http://wiki.ecmascript.org/doku.php?id=harmony:classes includes the concept 
> of private instance members and syntax for defining them.  While it presents 
> a syntax for accessing them (eg, private(foo).bar accesses the private 'bar' 
> member of the object that is the value of foo) there does not yet appear to 
> be consensus acceptance of this access syntax.

Oh, quite the opposite -- everyone on TC39 with whom I've spoken agrees that 
private(this) syntax is straw that must be burned up. We need new syntax, or 
else we need to do at least what Dave proposed in "minimal classes": defer 
private syntax, let programmers use private name objects and explicit [] 
indexing.

I do think we can say a few more things about private in class that may not be 
in the requirements on the wiki:

On the level of rationale for why class- and not instance-private, Juan Ignacio 
Dopazo in private correspondence made a good observation, shown by his example:

class MyClass {
  private foo() {}
  bar() {
    var self = this;
    setTimeout(function () {
      self.foo();
    }, 0);
  }
} 

Because |this| is not lexical, instance- rather than class-private access that 
requires "this." to the left of the private variable reference does not work 
unless you use the closure pattern explicitly and abjure |this|.

The straw "private(foo)" syntax doesn't help if the goal is instance privacy, 
since the inner function has no idea (runtime, never mind compile-time) how to 
enforce to which particular instance self must refer.

Requiring .bind(this) after the function expression passed to setTimeout can be 
used to work around such a hypothetical, mandatory "this."-prefix 
instance-private restriction, but that's onerous and it can be too costly.

Another observation about any class-private scheme we might consider in the 
current context: private instance variables in many ways (notably not for 
Object.freeze) act like properties, and the syntax mooted so far casts them in 
that light. Even if the ES5 reflective APIs, such as 
Object.getOwnPropertyNames, rightly skip privates on a class instance, proxies 
may raise the question: how does a private variable name reflect as a property 
name?

  class Point {
    constructor(x, y) { private x = x, y = y; }
    equals(other) {
     return private(this).x is private(other).x &&
            private(this).y is private(other).y;
    }
    ...
  }

We cannot know how to ask for private-x from other without special syntax of 
some kind, either at the access point or as a binding declaration affecting all 
.x (and x: in object literals). So here I use the proposal's straw private(foo) 
syntax.

Could other be a proxy that somehow has a private data record? Could other 
denote a class instance whose [[Prototype]] is a proxy? I claim we do not want 
private(foo) by itself, no .x after, to reify as an object, but if it did, then 
it seems to me it could be used with a proxy to reflect on private variable 
names.

There are certainly several choices here, but the one I currently favor as 
simplest, which creates no new, ad-hoc concepts in the language, is that 
class-private instance variables are properties named by private name objects.

Per the requirements for private in the classes proposal, this means 
Object.freeze does not freeze private-named properties, or at least does not 
make private-named data properties non-writable.

Perhaps Object.preventExtensions should not restrict private-named properties 
from being added to the object. This seems strange and wrong at first, but if 
freeze does not affect private-named properties, I'm not sure there is a 
"defensive consistency" threat from attackers decorating frozen objects with 
ad-hoc properties named by private name objects that only the attacker could 
create or access, which cannot collide with the class's private names.

Perhaps this is uncontroversial. I hope so, but I don't assume it is, and I 
suspect people who worked on the classes proposal may disagree. Cc'ing Mark in 
particular, since I'm just writing down some preliminary thoughts and 
intermediate conclusions here, and I could be way off base.

Ok, back to your good point about wanting private names to be usable in object 
initialisers:


> Each of these approaches seem plausible.  For a side-by-side comparison of 
> the above example using the alternatives see 
> http://wiki.ecmascript.org/lib/exe/fetch.php?id=harmony%3Aprivate_name_objects&cache=cache&media=harmony:private-name-alternatives.pdf
>  .  I'm interested in feedback on the alternatives.

The first thing I'd say is that, whatever the syntax (private prefix, [] around 
property name, or @ prefix), it seems too verbose to require boilerplate of 
const __x = Name.create(), etc. before the object literal.

Wouldn't it be better for the prefix, brackets or sigil to by itself define a 
private name and use it, also putting it in scope for the rest of the 
initialiser? With temporal dead zone error semantics for use before def, as 
with const?

On the syntax menu, the [] bracketing seems to allow arbitrary computed 
property names, but if I'm reading you right, you don't propose that: rather 
you want "constant" but not static property names, so that the initializer's 
shape does not depend on evaluating arbitrary expressions to compute property 
names (whether string-equated public names, or private name objecs). Do I have 
this right?

If so, I agree we want the syntax to should "here is a private property name!" 
In this light, private works but is verbose, @ works as well and is concise 
(maybe too concise for some folks).

I also contend that the static (compile-time, early-error time) shape of object 
literals in JS, in contrast to the mandatory name-quoting and full evaluation 
of unquoted name expressions in other languages such as Python, is something to 
consider keeping.

If so, then const is not enough. We would really need a static evaluation stage 
where private names could be created and used, but no other expressions 
evaluated. But such a stage has been rejected in the Harmony era, e.g. for 
guards.

Modules add a different kind of staging that is not problematic, but two stages 
for evaluating any given expression or statement is a bridge too far. I'm not 
in favor of adding another such evaluation regime.


> I've only used object literal in these examples, however the same 
> alternatives should be equally applicable to class declarations.

With classes as proposed, though, the way private name objects would be created 
would be via "private x = x, y = y;" declarations within the constructor body, 
as in my Point example above. That seems unfortunate since the scope of these 
names, whatever the access syntax, is wider than the constructor body. This is 
one of the open issues with classes I've mentioned here but not quite captured 
on the wiki page.

But whatever the class syntax, and the disposition of private in class and even 
classes in ES.next, I agree we should expect private declarative and expression 
forms to work the same in object initialisers and in classes.

It would be good to get everyone buying into this 
private-means-property-with-private-name-key-everywhere agreement.

/be
_______________________________________________
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss

Reply via email to