strawman for the := operator

Allen Wirfs-Brock allen at wirfs-brock.com
Wed Aug 8 11:30:17 PDT 2012


On Aug 8, 2012, at 9:35 AM, Brendan Eich wrote:

> Erik Corry wrote:
>> Hi
>> 
>> This proposal offers a way to get around some of the strange semantics
>> of '=', specifically the way read-only properties and setters on
>> objects in the prototype chain can restrict what you can do on the
>> receiver of an assignment.
> 
> This is "strange" only insofar as you can't say what you mean if you want to override. There's no law of nature requiring = to override, though.
> 
> Assigning != defining in ES5, even in reality in fixed implementations of ES3, and in truth going back to the first JS implementation: proto-setters (internal, hidden) are invoked by assignment, readonly proto-props prevent = being used to override on a delegating object (silent failure, of course, due to lack of try/catch).
> 
> What I'm getting at: is assignment != defining strange, or is the lack of expressiveness that left JS with = but not := strange, or is = not defining strange? I didn't want to assume the last was what you meant, since it is not obvious and not the only possible strangeness or asymmetry.
> 
>>   However it has some strangeness itself:
>> 
>> * There is little point in having read-only properties if the common
>> way to do assignment is :=.  := will just walk all over a read-only
>> property.
> 
> No, readonly properties must be {writable: false, configurable: false} to have integrity, and := cannot redefine a non-configurable property.

And, := should not be thought of or become the common way to do assignment.   That should remain the job of =
> 
>> * Copying private members from one object to another violates the
>> encapsulation pretty badly.  You would hope that using private names
>> allowed you to easily reason about which objects have which
>> properties, just by looking at the limited number of places a private
>> name is used.  But with this any code in the system that has two
>> instances of a class can splat object a's private properties with
>> those from object b.  It's rather like a replay attack in crypto.
> 
> Yes, this is an open issue in my view. If one uses a private name to brand an object, attackers who have access to such an object can use := to forge trojan objects.

"Encapsulation"? ES doesn't have any encapsulation...

I originally thought that I would spec. := to ignore properties with private names (but not those with just unique names). As I thought about this more, I realized that in many cases this was likely to violate the user's intent when using :=.

Here is a trivial example, that is only intended to be illustrative of more likely scenarios:

//this would all be modularized in some manner
const px = Name.private(), py = Name.private();   //I'm not sure what this API is ultimately going to look like
let PointLike = {
     get x() {return this[px]},
     set x(v) {this[px] = v},
     get y() {return this[py]},
     set y(v) {this[py] = v}
};
Object.defineProperty(PointLike,px,{value: writable: true});  //@px: 0 in the above obj lit would be so much nicer..
Object.defineProperty(PointLike,py,{value: 0, writable: true});

//somewhere else in program:

myObj := PointLike;  // mixin the PointLike properties 

Presumably, the above mixinobject would advertise that it provides public 'x' and 'y' properties, but it doesn't advertise or otherwise reveal the private names of the  px and py properties.

If := does not replicate the private named properties that the public properties are dependent upon then the mixin won't work. Essentially, the public and private named properties form a cohesive unit that needs to be replicated as a unit.  But this don't violate the secretness of those private names.  As long as the original definer of the names has protected them as a secret then only the public methods they provide that know the secret names can actually reference those properties. 

This does mean that the simple existence of some specific private named property is insufficient to serve as a reliable brand (for some meaning of brand).   Such brand properties need to be own properties, otherwise __proto__ tweaking could be used to circumvent such branding.  So,  there is a simple workaround.  When defining a own brand property set the value of the property to the object.  Then a brand check would look like:

   function isGenuine(obj) {return this[mySecretBrand] === this}

Cloning the mySecretBrand property of an object breaks the branding.  This, or similar identify based techniques could also be a solution to the "like a replay attach" issue.

Finally, I do have a way that we could put the cloning of private named properties by := under programmer control.  Note that private named properties are never enumerated or exposed via reflection.  Hence, the [[Enumerable]] attribute really doesn't mean anything for such properties.  We could enhance the semantics of := so that used the value of the [[Enumerable]] attribute to control the whether or not private named (and only private named) properties are cloned.  I'm not thrilled with this idea, but it probably could work. 

Allen



-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20120808/77886827/attachment-0001.html>


More information about the es-discuss mailing list