W3C home > Mailing lists > Public > public-webapps@w3.org > January to March 2015

Re: Custom element design with ES6 classes and Element constructors

From: Boris Zbarsky <bzbarsky@mit.edu>
Date: Tue, 13 Jan 2015 13:08:26 -0500
Message-ID: <54B55F1A.6090801@mit.edu>
To: Domenic Denicola <d@domenic.me>, "public-webapps@w3.org" <public-webapps@w3.org>
On 1/13/15 12:50 PM, Domenic Denicola wrote:
> Agreed. That needs to be done with <img is="my-img">, IMO. (Assuming the upgrading design doesn't get switched to DOM mutation, of course.)
>
> Although! Briefly yesterday Arv mentioned that for Blink's DOM implementation there's no real difference in "internal slots" between <img> and <span>: both just have a single internal slot pointing to the C++ backing object.

Just a few notes:

1)  This is not universal across implementations.  For example, Gecko 
will handle some property accesses by storing the values in additional 
internal slots on IDL objects.  We're not doing that on any elements 
right now, but would likely start doing that for HTMLMediaElement's 
TimeRanges attributes, for example, if those ever switch away from the 
"return a new object on every get" behavior.

2)  Updating the value in the internal slot means changing the C++ 
object identity, which means finding all the C++ places that have 
pointers to it (like the DOM tree) and ... something.  Not updating the 
value in the internal slot means you now have an <img> pointing to the 
wrong C++ class or something.

In any case, we seem agreed that for now this case needs to stick to the 
is="" syntax.

> The argument for different constructors is that: **assuming we want a design such that parsing-then-upgrading an element is the same as calling its constructor**, then we need the constructor to be split into two pieces: allocation, which happens on parse and is not overridden by author-defined subclasses, and initialization, which happens at upgrade time and is what authors define.

Right, that makes sense.

> However, when authors design constructors with `class C1 extends HTMLElement { constructor(...) { ... } }`, their constructor will do both allocation and initialization. We can't separately call the initialization part of it at upgrade time without also allocating a new object.

Hmm.

So this is a situation where having the [[Call]] of the constructor do 
something "magic" (like ignoring the super() call in the script) might 
be nice, but I agree it would be really weird.

> Thus, given a parse-then-upgrade scenario, we can essentially never call C1's constructor.

Yes, agreed.

> We *could* call some other method of C1 at upgrade time. Say, createdCallback.

Right.

> We could even generate a constructor, call it C2, that does HTMLElement allocation + calls createdCallback. That's what the current spec does.

OK. Or we could leave that up to the class implementor.  That is, they 
could do:

   class C1 extends HTMLElement {
     constructor(...args) { super(...args); this.createdCallback(); }
   };

if they want a nontrivial createdCallback.  It does mean more 
boilerplate, though.

I guess that's basically Arv's proposal, yes?

I'm less worried about the extra leeway in this setup per se and more 
worried about whether the extra leeway would be a footgun in practice...

Thank you for explaining; I see the issues more clearly now.

-Boris
Received on Tuesday, 13 January 2015 18:08:56 UTC

This archive was generated by hypermail 2.3.1 : Friday, 27 October 2017 07:27:25 UTC