Re: [heycam/webidl] Define a callback constructor type (#701)

@bzbarsky So here's what I was thinking:

- `constructor` dictates what prototype the function may be constructed as, similar to how `callback` types dictate the prototype functions may be *called* as.

- Static attributes are read as if the type were a `dictionary`. So these two are equivalent mod the requirement values implementing `Type` must also be constructible in the second case.

 ```
 dictionary Foo {
  Type someStaticProp;
  Type someStaticProp = "default";
  required Type someStaticProp;
  Type someStaticMethod(Foo someFoo);
 };

 interface dictionary Foo {
  constructor(...);
  static Type someStaticProp;
  static Type someStaticProp = "default";
  required static Type someStaticProp;
  static Type someStaticMethod(Foo someFoo);
 };
 ```

- Non-static attributes are based on the value returned from the constructor. So assuming the `callback` type was only constructed and never called, these two types would be functionally equivalent mod the extra binding that would not be exposed by the callback interface:

 ```
 callback Foo = FooInstance (double a, double b);
 dictionary FooInstance {
  Type someInstanceProp;
  Type someInstanceProp = "default";
  required Type someInstanceProp;
  Type someMethod(...);
  required Type someMethod(...);
 };

 interface dictionary Foo {
  constructor(double a, double b);
  attribute Type someInstanceProp;
  attribute Type someInstanceProp = "default";
  required attribute Type someInstanceProp;
  attribute Type someMethod(...);
  required attribute Type someMethod(...);
 };
 ```

 (Of course, it might be useful to allow referencing the type and value separately, but that's something that can be hashed out later.)

- Interface dictionaries can inherit from other interface dictionaries, in which they inherit all constructors, static properties, attributes, methods, and so on. If a `constructor` is specified, none of its parents may have them, and if no `constructor` is specified, at most one of them may have a `constructor`. If an interface dictionary does not inherit from other interface dictionaries, it may have at most one `constructor`. Outside of interface dictionary inheritance, they may only be referenced if a `constructor` is present.
 - They cannot inherit from interface mixins or ordinary dictionary types, but this restriction could likely be lifted for the latter.

- Interface dictionaries can inherit from a single interface provided it has a `constructor`. In this case, values must extend that interface (and not be identical to it) to be valid, and they must return an instance of that interface. If those two conditions are not fulfilled, a `TypeError` is thrown.
 - There might be other conditions that need added here - I can't remember the exact nuance involved in the custom element upgrade steps, and I'm not very familiar with the precise way the other specs handle required subtyping. I know the custom element API has other invariants it checks, too, but I'm not sure how much that carries over elsewhere.
 - The interface inherited from *must* feature the `[Exposed]` extended attribute. (Otherwise, it's a pretty useless requirement. It does however avoid the need to reify interfaces themselves into literal identities of some form.)

I was trying to avoid over-specifying here, and I probably left a few holes here by accident. But hopefully this clarifies what I'm suggesting. The overarching goal is to have a solution that solves the needs at hand flexibly while still being intuitively WebIDL. (And implementations can just desugar, abstract, and track a few new invariants - it's not a radical change to implement.)

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/heycam/webidl/issues/701#issuecomment-562828676

Received on Saturday, 7 December 2019 08:31:18 UTC