- From: Simon Pieters <simonp@opera.com>
- Date: Tue, 20 Dec 2011 11:06:29 +0100
- To: public-script-coord@w3.org, "Cameron McCormack" <cam@mcc.id.au>
On Tue, 20 Dec 2011 03:15:06 +0100, Cameron McCormack <cam@mcc.id.au>
wrote:
> There are several currently open issues that relate to operation
> invocation:
>
> * a request for union types [LC-66]
> http://www.w3.org/Bugs/Public/show_bug.cgi?id=14188
>
> * a (now withdrawn, but probably not unreasonable) request to be able
> to distinguish objects and arrays when overloading [LC-67]
> http://www.w3.org/mid/op.v1y3anre64w2qv@annevk-macbookpro.local
>
> * a request to remove [AllowAny] and make it the default for
> DOMString when overloading [LC-77]
> http://www.w3.org/mid/op.v3oo09cz64w2qv@annevk-macbookpro.local
>
> * a need to make not-exactly-matching types passed to overloaded
> operations behave the same as non-overloaded operations
> http://www.w3.org/mid/4EDD94BA.4000503@mcc.id.au
>
> I think we can satisfy the above requirements regarding overloading by
> further restricting the situations where it's allowed and by relying on
> union types. The main restriction that we make is to disallow
> overloading between primitive types (float, bool, long, etc.) and
> DOMString. There are no APIs at the moment that need this.
>
> So the following is disallowed:
>
> void f(Node n, float x);
> void f(Node n, DOMString x);
>
> As is this:
>
> void g(Node n, float x, DOMString y);
> void g(Node n, DOMString x, float y);
>
> which is a case where simply preferring DOMString conversions over
> others would not solve the overload resolution when called like
>
> g(node, "ab", "cd");
>
> unless we look at the ordering of the operations in the IDL. Simon
> showed where that's not going to work.
>
> The following is still allowed, since overloading discriminates based on
> argument list length before looking at argument types:
>
> void h(Node n, float x, float y);
> void h(Node n, DOMString x);
>
> Union types would be allowed to specify a primitive type and DOMString
> in the one union. For conversion from JS values in this case, DOMString
> would be preferred. That allows the first invalid example above to be
> rewritten as:
>
> void f(Node n, DOMString or float x);
>
> while the second invalid example could be rewritten as:
>
> void g(Node n, DOMString or float x, DOMString or float y);
>
> and then, if necessary, prose can be used to throw an exception if x and
> y are both strings or both floats.
>
> The new definition of distinguishable will exclude (primitive,
> DOMString), but union types will allow any combination of
> distinguishable types in addition to allowing a primitive type and
> DOMString to coexist.
>
> The rule remains that for each pair of overloaded operations, there must
> be at least one argument index where the two types at that position are
> distinguishable. This means that the following is allowed:
>
> void i(Node n, float x);
> void i(float x, Node n);
>
> but that when called as
>
> i(1, 2);
>
> the overload resolution algorithm would end up with no candidates, and
> an exception would be thrown.
>
> Two union types are distinguishable if all elements of the first are
> distinguishable with all elements of the second.
>
> Note that primitive types and DOMString are the only types that can get
> values from inexactly matching JS values passed in -- a Boolean is not
> needed for bool (ToBoolean is used to convert), a String is not needed
> for DOMString (ToString is used), etc. All the other types -- interface
> types, object, dictionaries, sequences, arrays, Date -- do not get any
> conversions; either the JS value passed in is an exact match for the
> type or it isn't.
>
> Per http://www.w3.org/mid/4EEFE632.9010506@mcc.id.au I think we should
> remove the ability for plain, non-Array JS objects to be considered as
> sequences. Objects like NodeLists can still be considered sequences,
> but rather than assuming this by looking at its length property, we just
> look at the indexed properties on the object. Interfaces with indexed
> properties are now not distinguishable from sequence types.
>
> We should also disallow overloading between two interface types if it is
> possible for an object to implement both interfaces. To handle such
> cases, spec authors can just use a union type instead.
>
>
> Ignoring the issue of explicitly passing undefined meaning "consider
> this an un-passed optional argument" and whether we want to revisit that
> (http://www.w3.org/mid/4EEEA0F0.5010906@mcc.id.au), overload resolution
> in this proposal goes as follows:
>
> * Generate the "effective overload set" for the given identifier
> and argument list length. Union types do not get expanded out
> into multiple entries like optional arguments do.
>
> * For each argument position:
>
> * For each entry in the effective overload set:
>
> * If the type is one of the exactly matching types mentioned
> above, or is a union type consisting only of the exactly
> matching types, and the JS value passed in does not match
> it, then disqualify this entry.
For nullable types, null is considered to match?
What about
void f(DOMString? x);
void f(Node? x);
Both would qualify if null is passed in (actually even if the DOMString
type isn't nullable).
Similarly, what about nullable unions?
void f(DOMString? or Node? x);
> * Assert: either all or all but one entries are disqualified.
>
> * If there is one entry left not disqualified, success, that's the one
> we call. Otherwise, throw.
>
>
> With all of the above:
>
> * We no longer need [AllowAny], as DOMString is always the selected
> type when overloading and an inexactly matching JS value is passed
> in.
>
> * We can have sequences where the element type does not have to be
> widened to "any" just so we can handle, say, Nodes and DOMStrings.
> We can just write sequence<Node or DOMString> instead.
>
> * We simplify a bunch of overloading that is done just to support
> multiple interface types in one argument position. It means we can
> simplify drawImage from CanvasRenderingContext2D:
>
> typedef HTMLImageElement or HTMLCanvasElement or HTMLVideoElement
> DrawableElement;
>
> void drawImage(DrawableElement image,
> double dx, double dy);
> void drawImage(DrawableElement
> double dx, double dy, double dw, double dh);
> void drawImage(DrawableElement image,
> double sx, double sy, double sw, double sh,
> double dx, double dy, double dw, double dh);
>
> * We don't need to pay attention to the order of overloads given in
> the IDL.
>
> * We can write operations that overload distinguishing dictionaries
> and sequences.
>
> * We don't have the current undesirable behavior where an inexact
> match when calling an overloaded operation causes an exception to
> be thrown.
>
> In the HTMLOptionsCollection example Simon brought up in the other
> thread, where the current IDL is:
>
> void add(HTMLOptionElement element, optional HTMLElement? before);
> void add(HTMLOptGroupElement element, optional HTMLElement? before);
> void add(HTMLOptionElement element, long before);
> void add(HTMLOptGroupElement element, long before);
>
> If we call add(document.createElement("optgroup"), "1") then we now
> would correctly choose the fourth overload, since any inexact type
> matches select long rather than HTMLElement?.
>
> Those four overloads could be simplified into one using union types, if
> desired:
>
> void add(HTMLOptionElement or HTMLOptGroupElement element,
> optional HTMLElement? or long before);
>
>
> Again, thoughts on all of the above are welcome, especially if you find
> any problems with it.
Overall looks good to me!
--
Simon Pieters
Opera Software
Received on Tuesday, 20 December 2011 10:13:31 UTC