Making "super" work outside a literal?

Allen Wirfs-Brock allen at wirfs-brock.com
Sat Jun 25 03:58:25 PDT 2011


On Jun 24, 2011, at 2:57 PM, Sean Eagan wrote:

> On Fri, Jun 24, 2011 at 5:08 AM, Allen Wirfs-Brock
> <allen at wirfs-brock.com> wrote:
> 
>> I agree that  the Object.defineProperty should apply defineMethod semantics when processing a "get" or "set" attributed as these are essentially method definition operations.
>> I don't think it should do so for "value".
> 
> I think it is inconsistent to update |super| for "get" and "set", but
> not for "value".

I contend that using defineProperty to to specify the get or set function of an accessor property  is conceptually quite different from using defineProperty (or assignment) to modify the value of a data property.  A put/get function is tightly linked to the object in the sense that it is automatically and transparently invoked as a method (with an implicitly supplied |this| value) and defineProperty is the only way to imperatively create such a method.  As such defineProperty with a get/set attribute, to me, seems to clearly be a method definition (or perhaps better called method binding) operation.

The inconsistency is with defineProperty with the value attribute.  That operation can be used for two conceptually different purposes.  One purpose is simply to store a value for later retrieval, such a values include function objects. The other purpose is to associate a method with an object.  In legacy ES, there was no real need to distinguish between these purposes.   The introduction of |super| (and possibly  other ES.next constructs such as private instance state) makes it important to distinguish these use cases.  That is the reason for Object.defineMethod.  For compatibility reasons, we can't change the semantics of defineProperty/value because it could break the storage/retrieval use case of properties.  However, defineProperty/get/set is already a method binding operation.  Giving it new extended semantics in the presence of a new language feature (super) would be a forward compatible change.

Legacy ES:

"method" definitions:  defineProperty/data; defineProperty/get, defineProperty/put
data property definitions: defineProperty/data

defineProperty/data is ambiguous -- it can be either a method or data property definition

Es.next:

"method" definitions:  defineMethod; defineProperty/get, defineProperty/put
data property definitions: defineProperty/data

Also ES programmers to avoid this ambiguity and permits associating new semantics with method definition that does not interfere with existing use of defineProperty/data

(more below)
> 
>> It is possible that a data property is being used as a function valued data store rather than as a method binding on an object. For example, a property might be used to store a callback function.  Such a data-value function might reference |super|.  For example, it might be a function with a bound |this| that also uses |super|.  I don't thing we want the |super| binding changing in such situations.  (Looking at this another way, if such a transformation of done in Object.defineProperty and not in [[DefineOwnProperty]] then there would be a semantic difference between obj.prop=func and Object.defineProperty(obj,"prop",{value:func}) that we probably don't want to have.)
>> 
>> I introduced the concept of defineMethod to define a means to explicitly disambiguate  the attachment of a method and the setting of a data property value in situations where it makes a difference.  People will run into bugs where they used = or defineProperty with the value attribute when they really need to do a defineMethod but at least with defineMethod there is a way to fix this bug.
> 
> I agree, this is why I proposed the Object.defineSuperProperty
> solution, as an explicit means to update |super|.  It is like
> Object.defineMethod except that it allows you to use the
> "configurable", "writable", and "enumerable" attributes with methods,
> and is also an explicit means to update |super| for accessor getters
> and setters.
> 
> Object.defineSuperProperty also avoids a proxy trap because it can
> essentially have the same semantics as Object.defineProperty except
> that it creates functions with updated [[Super]] before passing the
> property descriptor to [[DefineOwnProperty]] where the
> "defineProperty" trap will be called.
> 
> Probably Object.defineSuperUsingProperty would be more accurate name.
> 
> Another option would be to add a boolean "updateSuper" argument to
> Object.defineProperty.
> 
> Another option would be an |Object.updateSuper(object, "foo")| which
> assigns functions with updated |super| to any "value", "get", and
> "set" attributes which contain functions which use |super| of an
> existing property, calling [[DefineOwnProperty]] with the new values.

If we are defining a new definitional function, I want it to be able to do something more general then then just update the super binding.  I also want it to be generalizable to deal with any future object/method binding semantics that introduced in ES.next or future revisions of the language. Object.updateMethod meets that criteria.  Object.updateSuper does not.

> ...
>>  Function.usesSuper(func)
> 
> Yeah, that would probably be a better spot for it.
> 
>> however, WRT usesSuper, I isn't clear if it is anymore necessary than usesThis, hasNestedFunctions, hasIfStatements, and potentially hundreds of reflective queries that might be made about a function.
> 
> It could be used to determine if you need to do an
> Object.defineSuperUsingProperty / Object.updateSuper /
> Object.defineMethod or whatever we land on.
> 

I don't want it to be necessary to make such determination.  That breaks implementation encapsulation of the method.   Someone installing a method should just say:
   Object.defineMethod(...)
without having to worry about the implementation details of the method.   Similarly, defining an accessor should simply be:
    Object.defineProperty(obj,name,{get:func1,set: func2)

Allen


More information about the es-discuss mailing list