Re: Prototype chain for objects that implement multiple interfaces

On 06/06/07, Cameron McCormack <cam@mcc.id.au> wrote:
> What should the prototype chain for an object that implements multiple
> interfaces looks like?  A single interface is simple enough:
>
>   NodeList = { an object }
>   NodeList.[[Prototype]] = Object prototype object
>   NodeList.prototype = { an object }
>   NodeList.prototype.[[Prototype]] = Object prototype object
>   NodeList.prototype.constructor = NodeList
>   NodeList.prototype.someFunction = { some function }

Well, if there is no [[Construct]] property on the NodeList that is
callable using
    new NodeList
I don't think the NodeList.prototype.constructor property should point
to the NodeList object. If there is a constructor that is callable in
that way then let it point there. If there is no such constructor then
there should not be a NodeList.prototype.constructor property.

Also I think you forgot two things:
    NodeList.[[Class]] = "Object"
    NodeList.prototype.[[Class]] = "NodeList"

(The ECMAScript built-in constructors all follow the pattern of having
[[Call]], so their [[Class]] is "Function" instead and their
[[Prototype]] is the initial Function.prototype. The DOM constructors
don't have [[Call]] so their [[Class]] should be "Object" instead. Or
some implementation specific value, but if we're specifying things
that are not interoperable anyway I think we can at least do the
sensible thing.)

>   nl = { an object }
>   nl.[[Prototype]] = NodeList.prototype

and
    nl.[[Class]] = "NodeList"

> What happens if an object implements multiple interfaces, e.g. an
> Element that is also an EventTarget?  I can imagine a way to handle this
> with prototypes, for example:
>
>   Node = { an object }
>   Node.[[Prototype]] = Object prototype object
>   Node.prototype = { an object }
>   Node.prototype.constructor = Node

Again
    Node.[[Class]] = "Object"

And it doesn't make sense to have a Node.prototype.constructor which
is not a constructor. But I'll stop repeating that for every case now.

>   Element = { an object }
>   Element.[[Prototype]] = Object prototype object
>   Element.prototype = { an object }
>   Element.prototype.[[Prototype]] = Node.prototype
>   Element.prototype.constructor = Element
>
>   EventTarget = { an object }
>   EventTarget.[[Prototype]] = Object prototype object
>   EventTarget.prototype = { an object }
>   EventTarget.prototype.constructor = EventTarget
>
>   elt = { an object }
>   elt.[[Prototype]] = { an object }
>   elt.[[Prototype]].[[Prototype]] = null
>   elt.[[Prototype]].[[Get]](P):
>       1. If O doesn't have a property with name P, go to step 4.
>       2. Get the value of the property.
>       3. Return Result(2).
>       4. Call the [[HasProperty]] method of the Element prototype
>          object.
>       5. If Result(4) is true, go to step 9.
>       6. Call the [[HasProperty]] method of the EventTarget prototype
>          object.
>       7. If Result(6) is true, go to step 11.
>       8. Return undefined.
>       9. Call the [[Get]] method of the Element prototype object.
>       10. Return Result(9).
>       11. Call the [[Get]] method if the EventTarget prototype object.
>       12. Return Result(11).
>
> The same question could apply to multiple inheritance (which is allowed
> by OMG IDL, but AFAIK is not used in any of the DOM specs).

Several interfaces may be implemented on the same object. In this
case, I suspect the browsers would be implementing the EventTarget
interface on the Element interface object, or the Node interface
object.

But yes, I can see how it would make sense to be able to chain
together inheritance like that, so that if a property was added to
either the EventTarget or the Element prototypes it was still
accessible from the object that implements both.

> This is probably not what browsers do in practice, though.  For example,
> Opera 9 has an addEventListener method directly on the Node interface
> prototype object (see http://mcc.id.au/2007/05/binding-tests/#t008),
> presumably because all Node objects in a document also implement
> EventTarget.
>
 > Any opinions on how to specify this?

I'd wish to say I had a reasonable opinion. I do have an idea about it
that is very similar to yours, but that would require a chaining
together of prototype chains, which likely would mean that the
multiple multilevel inheritance problem would have to be solved. I
doubt we'd want to go into that. But if we indeed do want to go into
that, the Python model makes best sense of all I've see so far. Just
use it for prototypes instead of classes. The inheritance list itself
doesn't have to be runtime resolved since it only applies to the DOM
and not any ES objects, implementations would probably hardcode it for
performance reasons.
<uri:http://www.python.org/download/releases/2.3/mro/>


Another possible way to go: Something that might make sense is to
conflate all the interfaces for something into a single inheritance
object delegation chain. E.g. an implementation could have all of
Document, DocumentLS, DocumentStyle etc. conflated into the Document
interface object so that the document only has a single prototype
object to delegate to. The obvious problem to this is that an
implementation then wouldn't be able to contain more than one
simultaneous Document implementation.
-- 
David "liorean" Andersson

Received on Wednesday, 6 June 2007 08:50:51 UTC