removing multiple inheritance

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

* 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


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.

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.

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.


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.

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

Received on Tuesday, 14 June 2011 00:16:31 UTC