Re: ES6 and upgrading custom elements

2015-01-07 Thread Anne van Kesteren
On Wed, Jan 7, 2015 at 5:53 AM, Domenic Denicola d...@domenic.me wrote:
 ... all instances of MyInputElement will get all internal slots and other 
 exotic behavior of HTMLInputElement.

That's why I tried to scope this thread to upgrading and not the script side.

The main question is how you tie MyInputElement to something like
my-input and have that actually work. It seems Dimitri's answer is
that you don't, you use input is=my-input in combination with a
(delayed) prototype mutation and creation callback. And you use
createElement(input, my-input) or the constructor on the script
side of things.


 Which is that the HTML standard should just define that 
 `HTMLInputElement.extends = input`.

We could have that I guess, but it still doesn't help with upgrading, does it?


-- 
https://annevankesteren.nl/



RE: ES6 and upgrading custom elements

2015-01-07 Thread Domenic Denicola
From: annevankeste...@gmail.com [mailto:annevankeste...@gmail.com] On Behalf Of 
Anne van Kesteren

 That's why I tried to scope this thread to upgrading and not the script side.

 The main question is how you tie MyInputElement to something like my-input 
 and have that actually work. It seems Dimitri's answer is that you don't, you 
 use input is=my-input in combination with a (delayed) prototype mutation 
 and creation callback. And you use createElement(input, my-input) or the 
 constructor on the script side of things.

Oh my goodness, I'm sorry. I completely misunderstood what was meant by 
upgrading. My fault entirely, as it's a well-defined custom elements term.

I see the problem now. I'll try to think on it harder and get back to you. In 
the meantime, apologies for derailing the thread.



Re: ES6 and upgrading custom elements

2015-01-06 Thread Dimitri Glazkov
On Tue, Jan 6, 2015 at 10:38 AM, Anne van Kesteren ann...@annevk.nl wrote:

 On Tue, Jan 6, 2015 at 7:06 PM, Dimitri Glazkov dglaz...@google.com
 wrote:
  Yes to the first question. I wasn't planning on doing anything different
  there.

 It seems simple prototype munging but not actually changing identity
 will fail for all but the basic cases of subclassing. E.g. if I
 subclass an HTMLInputElement I would expect it to have an internal
 [[value]] slot of sorts, but since the element created is a plain
 HTMLElement whose prototype is munged that will not be the case.


Right, that's why to create a valid custom element that subclasses
HTMLInputElement, you should use type extensions. With type extensions, the
HTMLInputElement is what's instantiated.

:DG


Re: ES6 and upgrading custom elements

2015-01-06 Thread Dimitri Glazkov
On Tue, Jan 6, 2015 at 10:59 AM, Anne van Kesteren ann...@annevk.nl wrote:

 On Tue, Jan 6, 2015 at 7:54 PM, Dimitri Glazkov dglaz...@google.com
 wrote:
  Right, that's why to create a valid custom element that subclasses
  HTMLInputElement, you should use type extensions. With type extensions,
 the
  HTMLInputElement is what's instantiated.

 But without using type extensions this will work (provided we sort out
 the other bits):

   class X extends HTMLInputElement { ... }
   document.registerElement(x-input, X)
   var xinput = new X

 It seems sad to require type extensions (and therefore requiring a
 more complicated version of document.registerElement) for translating
 this into markup.


You shouldn't need anything more complicated:

class X extends HTMLInputElements { .. }
X.extends = input // additional line.
document.register(x-input, X)
var xinput = new X



 Having actual subclassing in JavaScript, but not for elements unless
 you use some sort of hack seems sad.


The type extensions is a hack, I agree :(

:DG


Re: ES6 and upgrading custom elements

2015-01-06 Thread Anne van Kesteren
On Tue, Jan 6, 2015 at 7:54 PM, Dimitri Glazkov dglaz...@google.com wrote:
 Right, that's why to create a valid custom element that subclasses
 HTMLInputElement, you should use type extensions. With type extensions, the
 HTMLInputElement is what's instantiated.

But without using type extensions this will work (provided we sort out
the other bits):

  class X extends HTMLInputElement { ... }
  document.registerElement(x-input, X)
  var xinput = new X

It seems sad to require type extensions (and therefore requiring a
more complicated version of document.registerElement) for translating
this into markup.

Having actual subclassing in JavaScript, but not for elements unless
you use some sort of hack seems sad.


-- 
https://annevankesteren.nl/



RE: ES6 and upgrading custom elements

2015-01-06 Thread Domenic Denicola
This is all intimately tied to the still-ongoing how-to-subclass-builtins 
discussion that is unfortunately happening on a private TC39 thread. The 
essential idea, however, is that as long as you do

```js
class MyInputElement extends HTMLInputElement {
  constructor() {
super(); // this is key
  }
}
```

then all instances of MyInputElement will get all internal slots and other 
exotic behavior of HTMLInputElement. The `super()` call is the signal that the 
object should be allocated and initialized using the logic of HTMLInputElement 
instead of Function.prototype (the default).

This will require defining a constructor for HTMLInputElement, of course, but 
it's pretty predictable you wouldn't be able to create subclasses of something 
without a constructor.

I am not sure exactly how this fits in with an ES6-era 
document.registerElement. This is the right time to start thinking about that, 
certainly.

Off the top of my head, ideally document.registerElement should just be a 
registration call, and should not actually need to modify the constructor or 
create a new constructor as it does today. The generated constructor in [1] 
does nothing special that the above constructor (which consists entirely of 
`super()`) could not be made to do automatically, as long as the Element 
constructor was made smart enough. (`super()` eventually will delegate up to 
the Element constructor.)

To explain that in more detail I need one more probable-ES6 concept, which is 
the new target. In the expression `var x = new MyInputElement()`, ` 
MyInputElement` is the new target. Part of the ES6 subclassing story is that 
all superclass constructors will be passed an implicit parameter for the new 
target. So, when the `MyInputElement()` constructor calls `super()`, that calls 
the [[Construct]] internal method of HTMLInputElement, passing in the new 
target of MyInputElement. Similarly when HTMLInputElement in turn calls 
`super()`, that will call the [[Construct]] internal method of HTMLElement, 
still passing in the new target of MyInputElement. Etc. until Element also gets 
a new target of MyInputElement.

With this in hand we could see how to define a smart enough element 
constructor. It would first look up the new target in the custom element 
registry. If it is there, it retrieves the definition for it, and can do all 
the work currently specified in [1]. That means that the actual constructor for 
`MyInputElement` can be as above, i.e. simply `super()`.

[1]: 
https://w3c.github.io/webcomponents/spec/custom/#dfn-custom-element-constructor-generation

 Conceptually, when I wrote it I'd imagined that the constructor will be 
 called only when you explicitly invoke it (new FooElement...). When parsing 
 or upgrading, the constructor would not be called. The createdCallback will 
 be invoked in either case.

I do not think this makes any sense. All instances of a class can only be 
created through its constructor. createdCallback should be left behind as 
legacy IMO.

--

With all this in mind I do not think extends is necessary. I am less sure 
about this though so take what follows with a grain of salt. But anyway, IMO 
you should just look at the inheritance chain for the constructor passed in to 
registerElement.

Also there is a pretty simple hack if you still want extends. Which is that the 
HTML standard should just define that `HTMLInputElement.extends = input`. 
Then in Dmitry's

```js
class X extends HTMLInputElement { .. }
X.extends = input // additional line.
document.register(x-input, X)
var xinput = new X
```

the need for the additional line disappears since `X.extends === 
HTMLInputElement.extends === input`.

(I guess this breaks for classes that have multiple tag names :-/. But it is 
pretty weird that I can't define `class QQ extends HTMLQuoteElement {}` and 
then do both `q is=x-qq` and `blockquote is=x-qq`. You would think I 
could do both. More reason to dislike `extends`.)



Re: ES6 and upgrading custom elements

2015-01-06 Thread Anne van Kesteren
On Tue, Jan 6, 2015 at 6:13 PM, Dimitri Glazkov dglaz...@google.com wrote:
 That section needs to be updated, because the ES6 spec had shifted a little
 bit with regard to @@create. Filed
 https://www.w3.org/Bugs/Public/show_bug.cgi?id=27769.

Yeah, there's issues in general there, such as ES6 giving up on
explaining all of DOM :-(


 Conceptually, when I wrote it I'd imagined that the constructor will be
 called only when you explicitly invoke it (new FooElement...). When parsing
 or upgrading, the constructor would not be called. The createdCallback will
 be invoked in either case.

Would you do the prototype munging that is specified in
createdCallback today? (I think it would be more clear if we made
that prototype munging part of the upgrade algorithm by the way.) How
else would that work? Pass a reference to the old element and let the
developer handle it?


-- 
https://annevankesteren.nl/



Re: ES6 and upgrading custom elements

2015-01-06 Thread Dimitri Glazkov
On Tue, Jan 6, 2015 at 9:56 AM, Anne van Kesteren ann...@annevk.nl wrote:

 On Tue, Jan 6, 2015 at 6:13 PM, Dimitri Glazkov dglaz...@google.com
 wrote:
  That section needs to be updated, because the ES6 spec had shifted a
 little
  bit with regard to @@create. Filed
  https://www.w3.org/Bugs/Public/show_bug.cgi?id=27769.

 Yeah, there's issues in general there, such as ES6 giving up on
 explaining all of DOM :-(


  Conceptually, when I wrote it I'd imagined that the constructor will be
  called only when you explicitly invoke it (new FooElement...). When
 parsing
  or upgrading, the constructor would not be called. The createdCallback
 will
  be invoked in either case.

 Would you do the prototype munging that is specified in
 createdCallback today? (I think it would be more clear if we made
 that prototype munging part of the upgrade algorithm by the way.) How
 else would that work? Pass a reference to the old element and let the
 developer handle it?


Yes to the first question. I wasn't planning on doing anything different
there. And yes, I would like to fix the munging clarity as part of
https://www.w3.org/Bugs/Public/show_bug.cgi?id=27437.

:DG




 --
 https://annevankesteren.nl/



Re: ES6 and upgrading custom elements

2015-01-06 Thread Dimitri Glazkov
That section needs to be updated, because the ES6 spec had shifted a little
bit with regard to @@create. Filed
https://www.w3.org/Bugs/Public/show_bug.cgi?id=27769.

Conceptually, when I wrote it I'd imagined that the constructor will be
called only when you explicitly invoke it (new FooElement...). When parsing
or upgrading, the constructor would not be called. The createdCallback will
be invoked in either case.

:DG


On Tue, Jan 6, 2015 at 7:21 AM, Anne van Kesteren ann...@annevk.nl wrote:

 It's not clear to me from
 https://w3c.github.io/webcomponents/spec/custom/#es6 how the upgrade
 works. From the pre-ES6 setup you can work out through inference that
 upgrading is supposed to mutate the prototype of the element in
 question.

 But it seems that mutating the prototype is not sufficient for ES6. We
 want an element created through the constructor, no? (Let's leave
 aside the question for now as to how this subclassing would work,
 that's already discussed elsewhere.)


 --
 https://annevankesteren.nl/




Re: ES6 and upgrading custom elements

2015-01-06 Thread Anne van Kesteren
On Tue, Jan 6, 2015 at 7:06 PM, Dimitri Glazkov dglaz...@google.com wrote:
 Yes to the first question. I wasn't planning on doing anything different
 there.

It seems simple prototype munging but not actually changing identity
will fail for all but the basic cases of subclassing. E.g. if I
subclass an HTMLInputElement I would expect it to have an internal
[[value]] slot of sorts, but since the element created is a plain
HTMLElement whose prototype is munged that will not be the case.


-- 
https://annevankesteren.nl/