On Jul 18, 2011, at 11:32 AM, Brendan Eich wrote:

> Hawt.
> 
> A bit rough in that LHS <& RHS mutates LHS, whereas LHS <| RHS is pure and 
> produces a new object (which could be optimized to mutate RHS, note well!). 
> Both <| and <& are operators, to support chaining. Would it be better for <& 
> to be pure as <| is, and make an assignment operator form, LHS <&= RHS, that 
> expands to LHS = LHS <& RHS?

One way to think about <& is as a more declarative and more concise alternative 
to Object.defineProperties. I think there are plenty of use causes for the 
mutating extends.  For example, adding properties to the prototype object of a 
function.  Another issue is that the object you need to extend may already have 
been captured somewhere.  For example, a super.constructor call might have 
registered the object in a WeakMap and if <& created a new instance you would 
loose the identify relationship.

In practice, I think most of the more declarative uses such as adding own 
properties can be implemented (and perhaps even specified) such that no extra 
objects need to be created.

One thing that I think is still open is whether the RHS needs to be an 
ObjectLiteral or whether any object producing expression should be allowed.  
All the use cases  I have explored use an ObjectLiteral but I don't see any 
hazard (like would be the case if <| mutated the LHS [[Prototype]]) with 
allowing a non-literal value of the RHS.

> 
> Anyway, if I have <& right, then:
> 
> class SkinnedMesh extends THREE.Mesh {
>  constructor(geometry, materials) {
>    super(geometry, materials);
> 
>    public identityMatrix = new THREE.Matrix4();
>    public bones = [];
>    public boneMatrices = [];
>    ...
>  }
> 
>  update(camera) {
>    ...
>    super.update();
>  }
> }
> 
> from http://wiki.ecmascript.org/doku.php?id=harmony:classes would desugar to:
> 
> function SkinnedMesh(geometry, materials) {
>  return super(geometry, materials) <& {
>    identityMatrix: new THREE.Matrix4(),
>    bones: [],
>    boneMatrices: [],
>    ...
>  };
> }
> 
> SkinnedMesh.prototype = THREE.Mesh.prototype <| {
>  update(camera) {
>    ...
>    super.update();
>  }
> };

yes, plus you need a
   constructor: SkinnedMesh
in the object literal used to defined SkinnedMesh.prototype

> 
> Class-side inheritance could be done via
> 
> let SkinnedMesh = THREE.Mesh <| (function (geom, mats) { ... } <& { 
> classMethod() {...} });
> 
> This loses the hoisting of SkinnedMesh that the function declaration 
> desugaring gained "for free" -- another rough spot to smooth out.
> 
> There's still a usability argument for class syntax, certainly.

Perhaps, but a simpler class syntax is arguably a better class syntax and as I 
mentioned "static" properties are relatively rare.  If the class declaration is 
taking care of building both the class and instance side prototype chains then

class SkinnedMesh extends THREE.Mesh {
    ...
    } <& {
    classMethod() {...}
};

would take care of them without complicating the class declaration body.

> 
> Class syntax is also, for some folks, an attractive nuisance because of 
> single-inheritance OOP being oversold and very often the wrong paradigm. But 
> <& helps there too -- one can more conveniently make mixins (I must mean <&= 
> here, of course).
> 
> The last conflicting name wins, or so it seems from what you've written. The 
> compositional answer there is to seal properties you don't want anyone to 
> redefine by a conflicting extend operation. I'm assuming the internal method 
> used to update the LHS or populate the new copy of it is 
> [[DefineOwnProperty]], as with ES5 object literals, and not [[Put]].

   Exactly. Like I mentioned above, <& is I proposed it (your <&=) is 
essentially a syntactic shorthand for Object.defineProperties. 

Allen



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

Reply via email to