The proposal to solve the prototype chain with multiple inheritance
problem that was hashed out at the recent TC39 meeting, and which had
broad agreement, is as follows:
* Have two kinds of interface. One is more concrete (almost class-
like), since it results in objects/properties/methods existing in
the JS environment. The other is more abstract, and is used for
mixing in behaviour to the class-like ones.
* The concrete interfaces have only single inheritance. For concrete
interfaces, only a single name will be allowed on the RHS of the
colon.
* The abstract interfaces allow multiple inheritance, and get mixed
into the concrete interfaces using the ‘implements’ statement.
* The abstract interfaces are structural types, and thus don’t have a
name. All of the properties they would define go on the prototype
object for the interface on the LHS of the implements statement.
Only concrete interfaces get interface objects and prototype
objects. Thus there is no way to determine if an object implements
a given abstract interface.
* The mixin prototype object goes away.
* All abstract interfaces are thus implicitly [Supplemental] and
[NoInterfaceObject]. There’s no need to define [Supplemental]
then, and [NoInterfaceObject] might be able to be dropped.
* No special [[HasInstance]] behaviour is now needed, since the only
interfaces you can test with ‘instanceof’ are the concrete
interfaces, which form a single inheritance hierarchy. We can just
use the standard [[HasInstance]] behaviour of Functions.
* [PrototypeRoot] can go away, since there is no multiple inheritance
of concrete interfaces.
WebKit, Gecko, Chromium and IE people seemed happy with this.
One issue I thought of since then is what to do if mixin interfaces want
to define constants, and they want them to appear on an interface object
with the abstract interface’s name? This comes up in SVG, for example:
interface SVGZoomAndPan {
const unsigned short SVG_ZOOMANDPAN_UNKNOWN = 0;
const unsigned short SVG_ZOOMANDPAN_DISABLE = 1;
const unsigned short SVG_ZOOMANDPAN_MAGNIFY = 2;
attribute unsigned short zoomAndPan setraises(DOMException);
};
interface SVGSVGElement : SVGElement,
SVGZoomAndPan,
… /* various other interfaces */ {
…
};
So in the new system, SVGSVGElement (which ultimately inherits from
Node) is a concrete interface, and SVGZoomAndPan is an abstract one.
SVG 1.1 currently requires that `SVGZoomAndPan.SVG_ZOOMANDPAN_MAGNIFY`
be a property. So if SVG were rewritten to use Web IDL, and
SVGZoomAndPan were an abstract interface, then its constants would only
appear on SVGSVGElement (and SVGSVGElement.prototype).
We could say that a property SVGZoomAndPan exists on the global object,
and it just has the constants on it and no prototype property, but it
then does look like an interface object that you might want to use on
the RHS of an instanceof. Does it matter particularly that these
structural types could cause these objects-exposing-constants to exist?
An alternative would be to just require that the SVGZoomAndPan object
exists with these constants as a legacy-required thing, and that for
future (other) specs, script authors would just need to look up the
constants on the concrete interface being mixed in to.
--
Cameron McCormack ≝ http://mcc.id.au/