Re: [webcomponents]: Of weird script elements and Benadryl

On Apr 13, 2013, at 9:13 PM, Scott Miles wrote:

> >> I think if an element needs such custom behavior it should be required to use a "constructor=" attribute to associate an app provided constructor object with the element and
> 
> I don't like this because it requires me to make a global symbol. document.register, as you pointed out does not. In the original scenario, the nesting of the <script> in the <element> provided the linkage between them (however it played out), I hate to lose that. If you think this is a bogus objection, please let me know (and I will take it seriously). 

Well, all built-in HTML*Element constructors are global so making app defined custom elements also be global doesn't seem like it is introducing any new ugliness.  Regardless, I believe when I first described "constructor=" is suggest that its value should be interpreted as a script expression.  In that case you can say things like:

<element name="x-foo" constructor="appNamespace.FooElement"> 
</element>

<element name="x-foo" constructor="myExtensionRegistry.lookup('x-foo')"> 
</element>

etc.

> 
> >> the constructor should be specified in a normal <script> bock using normal JS techniques.
> 
> There is a practical problem that we cannot make a constructor using 'normal' techniques that creates a DOM node, so sayeth the Gecko guys (iirc). There was a suggestion to make the custom objects have-a node instead of be-a node, which has many positives, but we tried that in polyfills and the users revolted against 'this !== my-element-instance' inside their class.

What they are referring to is what in the TC39 world we call the "built-ins  subclassing problem". The issue is that many built-in objects (for example arrays) and many host objects have special implementation specific object representations that gives them special runtime characteristics and that simply inheriting from their prototype isn't enough to give an object created by a "subclass" constructor those special characteristics. 

In TC39 we use the term "exotic object" for any object with such special characteristics.  In ES specs. we talk about the [[Construct]] behavior of a  function.  This is the protocol that is followed when the new operator is applied to a constructor function.  The normal default [[Construct]] behavior is to allocated a new normal object and then to call the constructor function to initialize the state of that object. Exotic object typically have a different dispatch at a low level to  a special [[Construct]] implementation that knows how to allocate and initialize the appropriate form of exotic object.

Here are four ways to avoid the subclassing problem for custom elements:

1)  Only allow instances of custome dom elements to be instantiated using document.createElement("x-foo").  createElement would instantiate the appropriate implementation level exotic dom element object structure and then invoke the app provided constructor (with this bound to the new exotic instance) to initialize the instance.  

2)  Whenever a constructor is associated with an <element>  either via a "constructor=" attribute or via a call to document.register the implementation would modify (if necessary) the [[Construct]] dispatch of the app provided constructor to first crate an implementation specific exotic dom element object and then to call the provided constructor to do any app specific initialization.  This would allow saying things like: new HTMLXFooElement() to instantiate custom elements 

3) Provide a new API that "blesses" an app provided constructor as an DOM element constructor.  Only "blessed" constructors would be allowed to be associated with an <element>.  The "blessing" process would be essentially the same as describe for #2 above.

4) ES6 includes specified behavior that eliminates the built-in subclassing problem and browsers will be implementing it.  It does this by explicitly separating the instance creation step of the [[Construct]] protocol from the initialization step and allowing a subclass constructor to inherit its instance creation behavior from its superclass constructor.  That means that an expression such as:
     class HMTLXFooElement extends HTMLElement {
         constructor () {
             super();   //do any general HTMLElement initialization
             //subclass specific initialization
           }
      }

creates an exotic HTMLElement like object, performs general HTMLElement initialization and finally performs subclass specific initialization.  Note that any of the first three approaches could presumably be designed to recognize the ES6 style constructors as already being valid for custom elements

Allen

Received on Sunday, 14 April 2013 18:29:03 UTC