RE: removing multiple inheritance

I can offer my thoughts from an implementation point of view.

First, I think this is definitely the right direction, and I'm happy to see the spec moving in this direction.


>From: public-script-coord-request@w3.org [mailto:public-script-coord-
>request@w3.org] On Behalf Of Cameron McCormack
>Sent: Monday, June 13, 2011 5:16 PM
>
>One of the last major outstanding bugs in Web IDL is to get rid of multiple
>inheritance and the mixin prototype object.  When I, TC39 folks and others
>discussed this late last year, we came up with this proposal:
>
>* interfaces come in two types: regular interfaces and mixin interfaces
>  (Jonas argued for calling these “classes” and “interfaces” instead,
>  IIRC)
>
>* regular interfaces can inherit only from a single other regular
>  interface

In IE9's implementation, we also allow mixin interfaces to have single-inheritance. When such an interface is used as the RHS of an implements statement the list of relevant APIs to copy includes APIs from that interface's inheritance chain (in addition to including mixin interfaces that are implemented by other mixin interfaces). For example, we have the following:

[NoInterfaceObject]
interface ScreenView : AbstractView { /* APIs */ }

[NoInterfaceObject]
interface AbstractView { /* APIs */ }

//Window implements AbstractView; // (included by inheritance from ScreenView)
Window implements ScreenView;

Another example:

[NoInterfaceObject]
interface SVGLocatable { /* APIs */ }
    
// Interop: Interface object does not exist in Safari 4, Opera 10; interface-only in Firefox w/no properties
[NoInterfaceObject]
interface SVGTransformable : SVGLocatable { /* APIs */ }

SVGGElement implements SVGTransformable;
SVGDefsElement implements SVGTransformable;
SVGUseElement implements SVGTransformable;
//...etc.

In practice, this capability is only used in 2-3 places and could quite easily be refactored if the extra complexity is not worth specing. (Can I say that refactoring the SVG spec into WebIDL in a mostly-interoperable way was quite an undertaking?) 


>* all regular interfaces get interface objects (unless
>  [NoInterfaceObject] is specified on them), and mixin interfaces never
>  get interface objects
>
>* in an “implements” statement, the interface on the RHS must be a mixin
>  interface
>
>* if there is an “A implements B” statement, then all properties for
>  operations/attributes/constants/etc. for B go on A’s interface
>  prototype object
>
>In starting to implement this change, I’ve realised that there is a case it
>doesn’t handle, which is when you have a mixin interface that not all
>objects of a certain type implement.  For example, in the HTML5 spec there
>are statements like this:
>
>http://whatwg.org/html/#loading-xml-documents

>  A Document object that is an XML document that was created by the
>  DOMImplementation.createDocument() factory method must also implement
>  the XMLDocumentLoader interface
>http://whatwg.org/html/#dom-showmodaldialog

>  The Window objects of Documents hosted by browsing contexts created by
>  the above [showModalDialog] algorithm must also implement the
>  WindowModal interface.
>
>So, not all Document objects implement XMLDocumentLoader, and not all
>Window objects implement WindowModal.  How should we handle these?
>Should we keep the concept of a mixin interface object to handle these
>cases?
>
>If we don’t want to, we could change the HTML spec to define
>XMLDocumentLoader as
>
>  interface XMLDocumentLoader : Document {
>    ...
>  };
>
>and say that the object returned from
>DOMImplementation.createXMLDocument is an XMLDocumentLoader object.
>(Renaming XMLDocumentLoader to XMLDocument probably makes sense in that
>case.)
>
>The WindowModal one is an interesting case, because for each distinct
>Window (global) object there is a whole set of interface objects,
>prototypes, etc.  So it would actually be safe to put the WindowModal
>properties on Window.prototype directly.  If you could restrict it just to
>the environment created by showModalDialog, you could
>
>  Window implements WindowModal;
>
>but as it stands the statement above would apply to all sets of “initial
>objects”. http://dev.w3.org/2006/webapi/WebIDL/#es-environment


Yes. And in IE9 we punted on a syntactic way of indicating this. I love Ian's magic syntax (now replaced with more descriptive spec language): 

Window implements WindowModal; // sometimes

This may be worth having a special declarative syntax...on the other hand, new specs should probably not do this type of conditional binding. I curious to hear what others think about this.


>Another problem, which I am not sure exists just yet, is what to do if you
>want to use an interface both as a concrete thing to inherit from and as a
>mixin.  Let’s take EventTarget as the example and assume we want to follow
>the recent changes to DOM Core to make it the super- interface of Node:
>
>  interface EventTarget { ... };
>  interface Node : EventTarget { ... };
>  interface XMLHttpRequest : EventTarget { ... };
>
>That works fine, and we can now monkeypatch EventTarget.prototype and
>affect Node and XHR objects.  But what if we have an existing interface
>hierarchy where we want to make a non-root interface implement
>EventTarget:
>
>  interface AbstractThingamy { ... };
>  interface InteractiveThingamy : AbstractThingamy { ... };
>  InteractiveThingamy implements EventTarget;
>
>That would be disallowed in this proposal, since the RHS of the implements
>statement is a regular interface.

In practice, we [IE9] haven't needed to support this yet. We treat EventTarget as [NoInterfaceObject] currently. However, if we changed to the above DOM Core proposal, then we'd have to do some refactoring of the object hierarchy to fit it in without using it in the RHS of an implements statement. 


>One of the advantages of the proposal was that by never having an interface
>prototype object for mixins, you avoid authors mistakenly thinking that
>modifying that object will affect all objects that implement that
>interface.  If we allow the above, then we have a distinct prototype object
>for EventTarget, and changes to it will affect Node and XHR objects but
>will have no affect on InteractiveThingamy objects.

...if you allow the above, this is the behavior that I would expect (because EventTarget.prototype would have one instance of the API, and InterfaceThingamy.prototype would have another copy).


>Another advantage was that by not having an interface object, we don’t have
>to worry about having custom [[HasInstance]] behaviour and we can always
>just rely on the native “look up the prototype chain”
>semantics.

Yep. The fewer alterations that the DOM has to make to the default JavaScript behavior, the better. That's my overall viewpoint.


>I think the strongest reason for reforming interface inheritance in Web IDL
>is to ensure that mixed-in interface properties get placed on the right
>objects.  So that, for example, the WindowTimers properties setTimeout etc.
>get put on Window.protoype, because `Window implements WindowTimers`.  I
>would be fine with not making the distinction between regular and mixin
>prototypes, bearing the cost of possible author confusion when
>modifications to EventTarget.prototype (in the example
>above) don’t affect InteractiveThingamy, and keeping [NoInterfaceObject]
>annotations on interfaces that really are mixins and which are unlikely to
>appear as the ancestore of another interface.  I think that is the simplest
>change to make, but I am interested to hear others’ opinions.

In either case, I'd rather *not* see a new type of interface just for mixins,
e.g., mixin Foo {} which might be equivalent to [NoInterfaceObject] interface Foo {}
because of the extensive use of [NoInterfaceObject] today.


>--
>Cameron McCormack ≝ http://mcc.id.au/

Received on Wednesday, 15 June 2011 21:20:20 UTC