-
Notifications
You must be signed in to change notification settings - Fork 160
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Proposal: allow subclasses of constructible built-ins to be constructed #125
Comments
We have to be a bit careful defining this, so if you do It might be simpler to just have IDL check whether the parent interface is in fact constructible instead of adding those provisions.
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
There totally are. Of the things Gecko implements, that would be the following:
I think the biggest problem is the behavior when one of those constructors is invoked. Say someone does
These problems come up in HTML too. If you do 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. |
But how does this work for subclasses that are constructible? E.g. if I do It seems to me like
I am in general convinced, but am curious about your thoughts on the above question first. |
No, if you do |
In particular, |
Sorry I keep coming back to this.. I think the key property is this: whatever adds the |
Oh, I see, I was assuming a normal ES model where subclasses called But I guess that's not how platform interfaces work. It sounds like they do a single allocation (and branding process) in their most-derived constructor, and only run that constructor's logic, not any base class constructors. That latter model probably makes more sense when you have a hierarchy of exotic objects. ES in general doesn't seem to have that; the closest it has is GeneratorFunction deriving from Function but it looks like FunctionAllocate (i.e. what does the allocation inside the Function constructor) has hard-coded knowledge of generator functions baked in to it. This is somewhat predictable as ES seems to make an implicit assumption that all of an object's slots are fixed at creation time. With this in mind I agree that we should do something specific to elements. Although, now I'm not sure what. I was thinking of just specifying a [PassThroughConstructor], but I guess that's not really what we want. We basically want to define that every HTML element class uses the same algorithm, which is currently only encoded in HTMLElement. Maybe I'll define [HTMLElementConstructor] in HTML, which says "the [[Construct]] behavior for this interface is as follows: ... algorithm currently only in HTMLElement goes here ..." |
That's not at all how things work at all in ES6 for builtins. The
Going back to ES builtins, the one case where there is inheritance is typed arrays. The way these are done in ES6 is that all the typed array classes have the same set of internal slots and the typed array constructors do in fact delegate to their proto (note, dynamically; I'm not sure whether you were proposing dynamic or static delegation in the HTML element constructors). Anyway, these all invoke There are no examples of ES6 builtins where builtin A subclasses builtin B and the set of internal slots differs between them, so we don't have a great guide to go on... Anyway, there are two ways to model this. One way is that creating an object requires its full set of internal slots, and then the creation has to be done by something that has all that information. In practice, that's the most-derived builtin constructor. This is the general approach ES6 takes, and the way actual implementations work, I believe. The other way is that you can dynamically add internal slots. As a specification device, this works ok: you call your super constructor, it adds whatever internal slots and branding, then you add your own internal slots and your own branding. The key is that we never have branding and internal slots diverge. This doesn't match how implementations work, but may make specification easier. The danger is if this setup allows creation of specifications that are not exactly implementable, due to the conceptual mismatch. But I think it's hard to do that in this case, as long as you don't add internal slots in weird conditional ways...
That might actually make sense, yes. But, again, we want this to be the built-in function object steps and use the normal built-in function object [[Construct]], I think. |
Previously, only HTMLElement itself ran the algorithm necessary to allow subclassing for the purpose of custom elements. This prevented most customized built-in elements from working correctly. Here we introduce the [HTMLConstructor] IDL extended attribute, in order to automatically install the correct constructor behavior for all HTML element constructors. Fixes #1289. See also whatwg/webidl#125 where an alternate solution was discussed and rejected before arriving at the solution contained here.
Closing this in favor of the [HTMLConstructor] solution in whatwg/html#1404. Thanks for talking me away from my weird idea, @bzbarsky! |
Previously, only HTMLElement itself ran the algorithm necessary to allow subclassing for the purpose of custom elements. This prevented most customized built-in elements from working correctly. Here we introduce the [HTMLConstructor] IDL extended attribute, in order to automatically install the correct constructor behavior for all HTML element constructors. Fixes #1289. See also whatwg/webidl#125 where an alternate solution was discussed and rejected before arriving at the solution contained here.
Originally: whatwg/html#1289
The problem
HTMLElement
has a constructor, specifically designed so that you can doHowever, our intention was that you should also be able to do
But this currently fails since, per Web IDL, the first step of
HTMLParagraphElement
's constructor is to throw aTypeError
.Proposed solution
For interface objects without [Constructor], change the first step of their constructor to only throw if they are not a derived interface. Otherwise, do the equivalent of
super(...arguments)
.This means all subclasses of things that are constructible automatically get a pass-through constructor.
Subclasses of things without constructors also get a pass-through constructor, but since the superclass constructor throws, the subclass constructor will continue throwing.
As part of this, I'd update the specification for interface objects to have modern [[Construct]] and [[Call]] definitions instead of just [[Call]].
Repercussions
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. If such interfaces exist, their subclasses would become constructible. This seems unlikely to be a problem even if such interfaces do exist, but it's hard to say for sure.
I'm happy to do a PR for this but would like some feedback on whether it will be accepted.
The text was updated successfully, but these errors were encountered: