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

On Fri, Nov 19, 2010 at 3:32 PM, Ian Hickson <ian@hixie.ch> wrote:
> On Sat, 20 Nov 2010, Cameron McCormack wrote:
>> Ian Hickson:
>> > This only removes one of the use cases for [Supplemental]; there are still
>> > some others, e.g. having a concrete interface be defined in several
>> > different specs (q.v. HTMLBodyElement),
>>
>> What specs other than HTML5 is HTMLBodyElement defined in?  Or is just
>> the two pieces in HTML5?  You could of course use a name on the part
>> that defines the presentational attributes and use an implements
>> statement.  Is there a reason that won’t work?
>
> Wouldn't that result in two interfaces in Java? There really is only one
> interface here, it's just specified in two different places.

Does that matter? Is Java an important enough use case that we need to
add special constructs just to keep the number of interfaces down?
Looking at SVG, it doesn't seem like Java people shy away from having
many interfaces.

> Another example is Navigator, which is defined in both Web Workers and
> HTML; they mix in various interfaces but the goal is for the platform to
> only have two Navigator interfaces (one for Window contexts, one for
> workers); the "abstract" interfaces don't exist as anything but a didactic
> aid in the spec(s).

You could do Navigator exactly the way you're currently do it, just
change the base object to use 'class' rather than 'interface'. So
something like:

class Navigator {
  // objects implementing this interface also implement the interfaces
given below
};
Navigator implements NavigatorID;
Navigator implements NavigatorOnLine;
Navigator implements NavigatorAbilities;

interface NavigatorID {
  readonly attribute DOMString appName;
  readonly attribute DOMString appVersion;
  readonly attribute DOMString platform;
  readonly attribute DOMString userAgent;
};

interface NavigatorOnLine {
  readonly attribute boolean onLine;
};

interface NavigatorAbilities {
  // content handler registration
  void registerProtocolHandler(in DOMString scheme, in DOMString url,
in DOMString title);
  void registerContentHandler(in DOMString mimeType, in DOMString url,
in DOMString title);
  void yieldForStorageUpdates();
};


and in workers spec

class WorkerNavigator {};
WorkerNavigator implements NavigatorID;
WorkerNavigator implements NavigatorOnLine;


Though really, i'm not sure what having all these interfaces buys you.
As an implementor of the relevant specs I feel that it's much more
readable to just have a single

class Navigator {
  // UA identification
  readonly attribute DOMString appName;
  readonly attribute DOMString appVersion;
  readonly attribute DOMString platform;
  readonly attribute DOMString userAgent;

  // online handling
  readonly attribute boolean onLine;

  // content handler registration
  void registerProtocolHandler(in DOMString scheme, in DOMString url,
in DOMString title);
  void registerContentHandler(in DOMString mimeType, in DOMString url,
in DOMString title);
  void yieldForStorageUpdates();
}

and in workers spec

class WorkerNavigator {
  // UA identification
  readonly attribute DOMString appName;
  readonly attribute DOMString appVersion;
  readonly attribute DOMString platform;
  readonly attribute DOMString userAgent;

  // online handling
  readonly attribute boolean onLine;
}


But clearly both solutions are solvable with the new WebIDL proposal.

> Another example is DOMException, where the interface has at various times
> been defined in various specs; e.g. for the moment the HTML spec has a
> [Supplemental] DOMException interface that adds a few codes. This will
> change once I get around to updating the spec for recent DOM Core changes,
> but the point is that when I do that change, it should have zero impact on
> any implementations, since they'd already just have a single interface {}
> block in their code, not two like in the spec.

Exceptions are a good question. In general I'd like to see WebIDL
better integrate with "native" JS exceptions.

>> > and having a hierarchy get flattened (e.g. DedicatedWorkerGlobalScope
>> > and SharedWorkerGlobalScope vs WorkerGlobalScope).
>>
>> So in this case, a WorkerGlobalScope can be either a
>> DedicatedWorkerGlobalScope or a SharedWorkerGlobalScope, is that right?
>
> Yes.

You should be able to use the same solution as described above:

class DedicatedWorkerGlobalScope {
  void postMessage(in any message, in optional MessagePortArray ports);
           attribute Function onmessage;
};
DedicatedWorkerGlobalScope implements WorkerGlobalScope;
DedicatedWorkerGlobalScope implements WorkerUtils;
DedicatedWorkerGlobalScope implements EventTarget;

class SharedWorkerGlobalScope {
  readonly attribute DOMString name;
  readonly attribute ApplicationCache applicationCache;
           attribute Function onconnect;
};
SharedWorkerGlobalScope implements WorkerGlobalScope;
SharedWorkerGlobalScope implements WorkerUtils;
SharedWorkerGlobalScope implements EventTarget;

interface WorkerGlobalScope {
  readonly attribute WorkerGlobalScope self;
  readonly attribute WorkerLocation location;

  void close();
           attribute Function onerror;
};

You could even do

interface WorkerGlobalScope : WorkerUtils, EventTarget {
  ...
};

to remove some of the 'implements' statements. It would have the exact
same meaning so no extra complications due to multiple inheritance.

Though again, I'm not sure that breaking out interfaces is very
beneficial for the readability of the spec. But if you really want to
do it, it seems like WebIDL has the tools.


>> They’d be concrete interfaces, but you don’t want there to be a
>> separate prototype for them?
>
> I want them to be concrete interfaces that don't inherit from anything,
> and there's only ever one of the two in any one context. However, I don't
> want to have to specify the common bits twice, and I want them to have the
> same name from the point of view of the programmers, but in the spec I
> need them to have different names so that I can define things for each one
> separately.

You don't have to specify a function twice just because it appears in
two interfaces. You can always refer to the first "copy" when
specifying the second.

>> > So we likely still need [Supplemental]. There's also the weird magic
>> > does for e.g. WindowModal, where the Window "class" is different in
>> > different contexts; should that just be done in prose?
>>
>> What is meant by the “class” being different?
>
> Poor terminology. I mean that the object's interface as seen from code is
> different -- specifically, a Window created by showModalDialog() has two
> extra members in its instance of "Window", there's no extra interface
> around. I guess it doesn't much matter how we do this particular one since
> anyone implementing Window in Java is going to want to shoot themselves
> pretty regularly anyway; that interface is just bonkers.

WebIDL aside this seems like a complicated situation. In ECMAScript,
would the prototype object be different in a showModalDialog-created
window from that of a "normal" window? Or would these extra properties
just appear as properties on the instance itself?

>> And then when I write up the new prototype stuff in Web IDL I’ll make
>> sure that when there is no implements statement that causes an abstract
>> interface to be implemented by an object, then the mixed in properties
>> go to the most derived concrete interface’s prototype.
>
> It might make sense just to have a "sometimes implements" statement that
> is required to have corresponding prose (much like we do with getters and
> setters), so one would say:
>
>   Window sometimes implements WindowModal;
>
> ...and then add the prose you suggest above.

I think what would make the most sense is to remove the WindowModal
interface entirely and just say that these appear as properties on the
instance. Having different prototype objects is pretty ugly.

/ Jonas

Received on Saturday, 20 November 2010 03:52:47 UTC