An "extend" operator is a natural companion to <|

Allen Wirfs-Brock allen at wirfs-brock.com
Tue Jul 19 10:15:21 PDT 2011


On Jul 18, 2011, at 7:24 PM, Axel Rauschmayer wrote:

>> From: Allen Wirfs-Brock <allen at wirfs-brock.com>
>> Date: July 18, 2011 19:32:24 GMT+02:00
>> To: es-discuss <es-discuss at mozilla.org>
>> Subject: An "extend" operator is a natural companion to <| 
> 
> 
> Definitely a nice dual to <|
> 
>> proto <| obj
> 
> 
> What happens if obj is not a literal? Then it would make sense to do a shallow copy of obj whose prototype is proto. That would be useful for combining objects into a chain.

That was my original thought, but for the proposal I limited to literal values on the RHS.  I did this to keep focus on the primary use cases and to not derail the feature with concerns about issues that don't occur in those primary use cases.   In particular there are some problematic issues relating to the concept of "shallow copy" of an arbitrary object.   What does that mean for host or Proxy based objects?  Is shallow copy a meaningful concept if the object uses closure capture to represent per object state? etc.

My think was that the feature could always be extended in the future to allow a non-literal RHS if we wanted to deal with those issues.


> 
> From your examples, it looks as if the lhs would be modified, a bit similar to the += operator. Then the "arrow" should probably point in the opposite direction, e.g.:
> 
>> objToBeModified +> increment

I don't follow your logic for the pointer direction. 


> 
> Quoting from your examples:
> 
>> function Point(x,y) {
>>    return tthis <& {
>>                   __x: x,
>>                   __y: y
>>                  };
>> };
>> Point.prototype <& {
>>    __validate(x,y) { return typeof x == 'number' && typeof y = 'number'}
>> };
> 
> 
> I love how the prototype is incremented here. What does "tthis" do? Wouldn't point simply return an object literal (no "this <&")?

No, because the [[Construct]] internal method set this to a new object whose [[Prototype]] is correctly initialized to Point.prototype.  You could return:
   Point.prototype <| { ...

As shown, in the immediately following constructor-based Point3D example, if you are going to build inheritance hierarchies using constructors like this you need to call the "super class" constructor.  If you think it is a good idea (it probably is) to always follow a common pattern for constructors then Point probably should have been written as:

function Point(x,y) {
   return Object.call(this) <& {
                  __x: x,
                  __y: y
                 };
};


> 
> Another example from your message:
> 
>> const Point = {
>>      //private members
>>      __x: 0,
>>      __y: 0, 
>>      __validate(x,y) { return typeof x == 'number' && typeof y = 'number'},
>>      //public members
>>      new(x,y) {
>>           if (!this.__validate(x,y)) throw "invalid";
>>           return this <| {
>>                   __x: x,
>>                   __y: y
>>                  }
>>       };
>> }
> 
> If things are ever done this way, I would prefer to have an initialize() method (that only initializes an instance that has been created for it) and not a method that instantiates and initializes at the same time. initialize() works together very well with super-references, because in subclasses, you simply call the super-initialize method.

Lots of possible patterns for these things.  I was just trying to illustrate key use cases and not suggest a recommend pattern.

Allen

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


More information about the es-discuss mailing list