Harmony classes [Was: Operator overloading revisited]

Tom Van Cutsem tvcutsem at vub.ac.be
Mon Jul 27 02:56:04 PDT 2009


>> Do I get it right that a trait composition conflict is only raised  
>> upon
>> accessing the conflicting property? In AmbientTalk, the error is  
>> signaled at
>> composition-time (i.e. as if your addTrait method would raise an  
>> exception).
>> What's your rationale for deferring the exception until the  
>> property is
>> accessed?
>
> This change of semantics was more exploratory than purposeful. A
> retroactive rationalization though is that a conflict that isn't used
> shouldn't need resolution. C++ does something like this for its
> multiple inheritance. Of course, they detect possible use statically
> as well, so they don't pay the price of delaying the failure till the
> use actually occurs.
>
> If desired, it would be simple to alter the scheme I posted so that it
> signals the conflict at composition time instead. I have no strong
> opinion on which we should prefer.

Me neither, as long as it's obvious to the programmer what composition  
caused the conflict.

>>> const isSameDesc(desc1, desc2) { ... }
>>>
>>> const addTrait(self, trait, opt_advice) {
>>>  const advice = opt_advice || {};
>>>  Object.getOwnPropertyNames(trait).forEach(const(k) {
>>>   const newDesc = Object.getOwnPropertyDescriptor(trait, k);
>>>   if (k in advice) {
>>>     const k2 = advice[k];
>>>     if (k2) { k = k2; /*String(k2); ? */ } else { return; }
>>>   }
>>>   const oldDesc = Object.getOwnPropertyDescriptor(self, k);
>>>   if (oldDesc) {
>>>     if (isSameDesc(oldDesc, newDesc)) {
>>>        // already cool
>>>     } else {
>>>        Object.defineProperty(self, k, conflictDesc);
>>>     }
>>>   } else {
>>>     Object.defineProperty(self, k, newDesc);
>>>   }
>>>  });
>>> }
>>> ------------------------

It's really nice that you can specify trait composition in Javascript  
using metaprogramming this easily. I checked your implementation  
against our implementation of traits in AmbientTalk. There is one  
issue that we had to work around, which relates to "default  
properties" that are present in every object: we had to exclude such  
properties 'by default' since they would otherwise always cause  
conflicts. My guess is that if such properties exist in JS, you would  
probably set their 'enumerable' field to false to filter them out.

>> I think it works because you represent methods simply as functions
>> (closures). I assume that newDesc's 'get' prope[r]ty refers to a  
>> function that
>> represents the trait method, and this function has closed over its  
>> lexical
>> scope and will correctly refer to lexically free identifiers even  
>> when
>> installed in a different object. Am I right?
>
> Yes, except for one detail. In this case, it is newDesc's 'value'
> property rather than its get property. Starting with ES5, a property
> is either a "data property" or an "accessor property". The descriptor
> of a data property has the form
>    { value: <any>, writable: <boolean>, enumerable: <boolean>,
> configurable: <boolean> }
> The descriptor of an accessor property has the form
>    { get: <function () -> any>, set: <function (any)>, enumerable:
> <boolean>, configurable: <boolean> }

Thanks for the clarification. Could you point me to a page that  
explains the rationale behind distinguishing data properties from  
accessor properties? At first sight, it appears you don't need both  
since accessor properties can easily subsume data properties.

Kind regards,
Tom


More information about the es-discuss mailing list