Re: an idea for replacing arguments.length

On 11/10/13 8:25 PM, Allen Wirfs-Brock wrote:
> Where the usual attempts at describing overloads for JS go wrong is it they either ignore dynamic coercions or forget in in real JS code they would happen after the overload selection.  WebIDL address this by building performing (known) coercions into its overload selection algorithm.  But I don't think any human JS programer would do it the way it does.

So the way WebIDL works right now is basically a 4-step process:

1) Select the set of valid overloads for the given argument count 
(basically, select all the overloads that might be callable with that 
many arguments, based on which arguments they have optional, etc).

2) Do dynamic coercions for arguments starting with the first one and up 
through the last one on which the elements of this set agree.

3) Select the right overload based on the first argument on which the 
remaining elements of the overload set disagree.

4) Finish doing dynamic coercions.

I agree that this is not how anyone would write this in practice.  Part 
of the reason for this is that this algorithm is trying to handle two 
types of overloading at once: overloading on argument count (step 1) and 
overloading on type of argument (step 3).  And there are complications 
from dealing with overloads of the "argument type" kind in situations 
where some of the overloads have (typed!) varargs at the end and 
whatnot, at least in theory.

In practice, though, APIs generally do one or the other but not both. 
To do both you'd need an API somewhat like this (in WebIDL):

   void foo();
   void foo(InterfaceType1 arg);
   void foo(InterfaceType2 arg);

where some overloads have to be told apart by number of arguments and 
some have to be told apart by the types of the arguments.

I just checked for APIs in Gecko's WebIDL where selection is happening 
based on argument count (in that there are overloads with different 
argument counts) and there are also some argument counts which have 
multiple overloads for them.  The upshot is that almost all of them can 
in fact be dealt with by picking an "overload" based on type of the 
first argument that doesn't match across all the overloads with just a 
few exceptions:

Document:
   TouchList createTouchList(Touch... touches);
   TouchList createTouchList(sequence<Touch> touches);

IDBFactory:
   IDBOpenDBRequest open(DOMString name, [EnforceRange] unsigned long 
long version);
   IDBOpenDBRequest open(DOMString name, optional IDBOpenDBOptions options);

URL:
   [Constructor(DOMString url, URL base),
    Constructor(DOMString url, optional DOMString base = "about:blank")]
interface URL {

WebSocket:
   [Constructor(DOMString url),
    Constructor(DOMString url, DOMString protocols),
    Constructor(DOMString url, sequence<DOMString> protocols)]

XMLHttpRequest:
   void send();
   void send(ArrayBuffer data);
   void send(ArrayBufferView data);
   void send(Blob data);
   void send(Document data);
   void send(DOMString? data);
   void send(FormData data);
   void send(InputStream data);

I believe even for all of these, we could treat them as overloads on the 
"type" of some argument, where we allow "undefined" as a type that 
matches the argument not being present or an argument being optional.

So a viable way forward in terms of WebIDL overloads, perhaps, is to 
simply disallow overloading on both argument count and argument types 
(modulo the proviso about undefined above, somehow) and require that 
overloads for a name either all have an argument that can be used to 
distinguish them from each other or take different argument counts but 
not both.  Or something.

This does nothing for getting rid of the need to check arguments.length 
in overloads that overload on the arg count, of course.  We could be 
more radical and recast it all in terms of examining types, treating 
missing arguments as undefined but that would break compat in at least 
canvas methods, unfortunately, and I don't think we _really_ want to go 
there.

On the other hand, what we probably _could_ do if we make the split 
above is make overloading on arg count explicitly deprecated (e.g. 
enforce in UAs that no new APIs that use it get added).

-Boris

Received on Monday, 11 November 2013 02:13:27 UTC