- 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