Re: [WebIDL] prototype chains, multiple inheritance, mixin interfaces

On 19/11/10 21:39, Cameron McCormack wrote:
> 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:
[removed TC39 proposal]

For our browser (ANT Galio Browser) we have implemented something that
we believe is close to implementing the current spec (described in terms
of mixin prototype objects) using multiple inheritance.

We use the same linearization as Python and Perl6, relevant links can be
found on wikipedia here:

http://en.wikipedia.org/wiki/C3_linearization

Because it is not possible to get an objects prototype (except for with
the completely non-standard, deprecated property __proto__), and the
WebIDL specification does not specify any odering we can inherit from
whatever we like without issue, as long as we have a sensible resolution
order (C3) and [[HasInstance]] implementation.

Our [[HasInstance]] implementation walks up the prototype chain directly
rather than using the linearization and only looks at the first
interface in the list if if we have multiple inheritance.

The list that [[HasInstance]] walks is the prototype chain to
[PrototypeRoot] (we make sure we specify those objects first in the
input to the linearization algorithm).  These are the same as the
"concrete" interfaces from the TC39 meeting proposal.

The advantages of this approach were:

* It was fairly easy to implement (but I'm not sure how much effort it
would be for others);
* We can have interface prototype objects for all of the interfaces and
updates to these will affect all objects that inherit from them;
* The constants work as expected;
* We don't need to allocate much memory - we create the interface and
interface prototype objects on demand so if you don't access them
directly they don't get allocated;
* We can use the same mechanism to make the global inherit from both
Window.prototype and the ECMAScript global object.

In terms of specification, it wouldn't seem unreasonable to simply have
the inherited interfaces in the appropriate order in the specification
and have the CS linearization code deal with it, so [PrototypeRoot] can
go away.  I think [Supplemental] and [NoInterfaceObject] have other uses
elsewhere so we have to keep those (but remove this use case).

The only real downside I can see of doing this is that we don't use the
[[Get]], [[CanPut]], and [[HasInstance]] described in the ECMAScript
specification because of our more complicated inheritance.  These
methods walk up the prototype chain by calling the same method on the
[[Prototype]] object, but we could have a linearization stored in there
which we will have to walk along.  On a positive note we actually use
the same implementation for all objects in the system - the behaviour is
not changed for objects with single inheritance.

We haven't seen any compatibility issues with this change, but our
browser doesn't get the same level of use that others do.  I don't think
this way of dealing with multiple inheritance has caused much confusion
for Python and Perl users, it tends to "just work" without really having
to think too much about it.

Is this a reasonable way of dealing with the problem?  Are there any
issues with doing this?  Is it any better than the proposal from the
TC39 meeting?

-- 
Andrew Oakley

Received on Tuesday, 23 November 2010 12:09:54 UTC