Re: [heycam/webidl] Proposal: allow subclasses of constructible built-ins to be constructed (#125)

> Otherwise, do the equivalent of `super(...arguments)`.

We have to be a bit careful defining this, so if you do `new Foo` and `Foo` inherits from `Bar`, the UA is allowed to throw an exception with text about `Foo` not being constructible, as opposed to `Bar` not being constructible.  Note that examining `new.target` is not sufficient to generate some text, because you might have subclassed `Foo`.  So we need some provision for this...

It might be simpler to just have IDL check whether the parent interface is in fact constructible instead of adding those provisions.

> As part of this, I'd update the specification for interface objects to have modern [[Construct]] and [[Call]] definitions instead of just [[Call]].

Note the discussion towards the end of https://www.w3.org/Bugs/Public/show_bug.cgi?id=22808 (comment 17 and following).  In particular, I'd think we want IDL constructors to just be built-in function objects, have the default [[Call]] and [[Construct]] of those, and examine `new.target` to see whether they were called as a constructor.  Otherwise we have to redefine a bunch of stuff involving the script execution context stack and whatnot...

> I'm not sure if there are any interface on the platform that currently have a constructor, but which have subclasses that are not constructible.

There totally are.  Of the things Gecko implements, that would be the following:

1. `Event` has the following non-constructible standardized subclasses: `AudioProcessingEvent`, `BeforeUnloadEvent`, `MediaKeyError`, `MutationEvent` (well, questionably standardized), `OfflineAudioCompletionEvent`, `TimeEvent` (again, questionably standardized).
2. `Text` has `CDATASection` inheriting from it, though I think some people are trying to remove it as a thing.
3. `Animation` has non-constructible `CSSAnimation` and `CSSTransition` inheriting from it.
4. `MediaStream` has non-constructible `CanvasCaptureMediaStream` and `LocalMediaStream`.
5. `UIEvent` has `CompositionEvent`, `SVGZoomEvent`
6. There's whatever is going on with documents (e.g. is `HTMLDocument` a thing, and is it constructible?).
7. `DocumentFragment` has non-constructible `ShadowRoot` inheriting from it.

I think the biggest problem is the behavior when one of those constructors is invoked.  Say someone does `new ShadowRoot`.  If this just forwards to `DocumentFragment` you get back an object with the following behaviors as far as I can tell:

* Object.prototype.toString.call() claims "[object ShadowRoot]" (because that's how `@@toStringTag` works, sorry.
* The object is branded as a `DocumentFragment` but not a `ShadowRoot` (because the branding is done at allocation time and the allocation happens in the `DocumentFragment` constructor).
* Doing `for (far i in obj) { console.log(i, obj[i]); }` throws, because the accessor props expect actual `ShadowRoot` branding.

These problems come up in HTML too.  If you do `class Foo extends HTMLParagraphElement` and then `new Foo` do you get an element with `localName` set to `"p"`?  If so, I guess that's because the `HTMLElement` constructor does the whole element registry thing and you must have registered your thing with the right info for that to work.  But it won't work without that bit...

I think the right answer here is probably to do something specific to elements, because they have this weird setup where the base class constructor creates subclasses based on some sort of out of band information.  For things that _don't_ do that, passthrough is not the right behavior.

---
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/heycam/webidl/issues/125#issuecomment-220727799

Received on Friday, 20 May 2016 21:56:07 UTC