Re: [WebIDL] Handling undefined in Overload Resolution Algorithm

On 20/07/11 1:04 AM, Lachlan Hunt wrote:
> Refer to discussion in a Mozilla bug 648722 [1].
>
> When undefined in passed to an overloaded function, the overload
> resolution algorithm should not exclude nullable non-primitive types.

Thanks for all the discussion in the thread.  It sounds like the 
following is what was settled on:

* When undefined is passed, it is always treated the same as if it was
   not passed at all.

* Overload resolution is performed after these undefined arguments at
   the end of a function call are "dropped".

* Anywhere an undefined would help select a nullable primitive type
   during overload resolution, it should help select nullable types
   regardless of the inner type.  (This would still matter in cases
   where explicit undefined is passed in the middle of the argument list,
   and later arguments are not undefined.)


I want to run through what that means with some examples.  In June I 
resolved the open issue about what to do with too few arguments being 
passed -- convert from undefined, or throw -- to throw.  (I couldn't 
find a mail on this list where I announced that resolution; maybe I 
forgot to send it.)  It might be that treating an explicit undefined as 
being like not having passed the argument at all feels inconsistent with 
throwing for too few arguments, not sure.  Anyway:

void f(in float x, in optional float y);

   The two overloads to select between are:
     (float)
     (float, float)

   f() === throw TypeError
   f(undefined) === throw TypeError
   f(null) === f(0)
   f(1) === f(1)
   f(1, undefined) === f(1)
   f(1, null) === f(1, 0)

void f(in float x, in float? y);

   There is only a single "overload":
     (float, float?)

   f() === throw TypeError
   f(undefined) === throw TypeError
   f(null) === throw TypeError
   f(1) === throw TypeError
   f(1, undefined) === throw TypeError
   f(1, null) === f(1, null)

void f(in float x, in optional float? y);

   Overloads are:
     (float)
     (float, float?)

   f() === throw TypeError
   f(undefined) === throw TypeError
   f(null) === f(0)
   f(1) === f(1)
   f(1, undefined) === f(1)
   f(1, null) === f(1, null)

void f(in float x);
void f(in float x, in float y, in float z);

   Overloads are:
     (float)
     (float, float, float)

   f() === throw TypeError
   f(undefined) === throw TypeError
   f(null) === f(0)
   f(1) === f(1)
   f(1, undefined) === f(1)
   f(1, null) === throw TypeError
   f(1, 2) === throw TypeError
   f(1, 2, undefined) === throw TypeError
   f(1, 2, null) === f(1, 2, 0)
   f(1, undefined, undefined) === throw TypeError
   f(1, undefined, 2) === f(1, NaN, 2)
   f(1, null, 2) === f(1, 0, 2)

And finally for the API at hand:

Element querySelector(in DOMString a, in optional Element b);
Element querySelector(in DOMString a, in sequence<Node>? b);

   Overloads are:
     (DOMString)
     (DOMString, Element)
     (DOMString, sequence<Node>?)

   querySelector() === throw TypeError
   querySelector(undefined) === throw TypeError
   querySelector(null) === querySelector("null")
   querySelector("a", undefined) === querySelector("a")
   querySelector("a", null) === querySelector("a", (sequence<Node>?)null)

Let me know your thoughts.

Received on Thursday, 4 August 2011 00:51:20 UTC