An experiment using an object literal based class definition pattern

Allen Wirfs-Brock allen at wirfs-brock.com
Mon Aug 8 11:06:08 PDT 2011


On Aug 8, 2011, at 3:39 AM, Andreas Rossberg wrote:

> On 4 August 2011 22:57, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:
>> Using these two new ideas and other active object literal enhancement
>> proposals it is pretty easy to compose a class-like declaration.  For
>> example the SkinnedMesh from
>> the http://wiki.ecmascript.org/doku.php?id=harmony:classes proposal can be
>> code as:
>>   const SkinnedMesh = THREE.Matrix4.Mesh <| function(geometry,materials){
>>     super.construtor(geometry,materials);
>>     this.{
>>       identity.Matrix: new THREE.Matrix4(),
>>       bones: [],
>>       boneMatrices: []
>>     };
>>   }.prototype.{
>>     update(camera) {
>>       ...
>>       super(update);
>>     }
>>   }.constructor.{
>>     default(){
>>       return new this(THREE.defaultGeometry,THREE.defaultMaterials);
>>     }
>>   };
> 
> Sorry for chiming in late, but I don't understand this example. My
> understanding so far was that <| takes a literal on its right-hand
> side.

In this case the literal is the FunctionExpression

> But that doesn't seem to be the case here. So what is the
> intended semantics? Does <| mutate the rhs object (that would make it
> equivalent to exposing mutable __proto__, which seems bad)? Or does it
> copy the object (then how is the copy defined)?

Your original understand is correct <| causes the "literal"  (in reality, an dynamic object generator) on its RHS to create its object using the LHS as its [[Prototype]] value.

> 
> Or do you consider <| to take precedence over .{}?

<| and . have the same precedence and are left associate.

> In that case, the
> example wouldn't make sense, because <| wouldn't see the prototype
> property.

You can think of the above expression as evaluating in the following steps.
1) THREE.Matrix4.Mesh ; evacuate THREE.Matrix4.Mesh  (I think the 2nd . is a typo, but it really doesn't matter for the example)
2) <| function() {}: Create a function object whose [[Prototype]] is the result of step 1.   That object has a "prototype" property whose value is a new object whose [[Prototype]] is the value of the "prototype" property of step 1. The prototype object has a "constructor" property whose value is the function object. The value of this step is the function object.
3) .prototype:  access the value the "prototype" property of the step 2 result
4) .{...}:  extend the object that is the result of step 3 by adding to it the methods defined by the object literal. These become properties of the prototype The value of this step is the same as the value of step 3.
5) .constructor:  access the value of the "constructor" property of the step 4 result.  This will be the original function object from step 2.
6) .{...}: extend the object that is the result of step 5 by adding to it the methods defined by the object literal. These become properties of the constructor function (ie, the "class") The value of this step is the same as the value of step 5.
7) =: bind the result of step 6 as the value of the const SkinnedMesh.  This is now essentially a named class.

While these are logically independent runtime steps, the "shape" of the prototype and constructor objects are inherent in the object literals and should be statically apparent to the compiler.

Allen



> 
> /Andreas



More information about the es-discuss mailing list