Re: [WebIDL] Converting non-objects to Dictionaries.

On 22/07/11 7:22 AM, Jonas Sicking wrote:
> dictionary FooOptions {
>   boolean reverse = false;
>   unsigned long limit;
> };
>
> interface Foo {
>    void someFunc(in DOMString name, optional in FooOptions options);
> };
...
> myfoo.someFunc("name", 4);
>
> The dictionary algorithm will convert the '4' to an object and then
> attempt to read properties off that object. However since the object
> won't have any properties, all properties in the dictionary will get
> their default value. In other words, the above is equivalent to
>
> myfoo.someFunc("name", {});
> and
> myfoo.someFunc("name");
>
> It seems to very likely that if someone passes in a non-object, they
> have a bug in their code and we would do them a bigger service by
> throwing an exception than silently ignoring their argument.

I agree.

> This does leave the question what to do for something like:
>
> myfoo.someFunc("name", null);
> and
> myfoo.someFunc("name", undefined);
>
> It seems useful to me to allow both these and use the default values
> in both cases. For example for code that looks like:
>
> function myDoStuffFunc(name, options) {
>    getFooObj().someFunc(name, options);
> }

At the moment, you could write

   interface Foo {
     void someFunc(DOMString name, optional FooOptions? options);
   };

so that null is a valid value of the second argument, and you write 
prose handling that case.  There's slight utility in allowing null (or 
undefined) versus { } -- for the cases that Allen brings up where the 
dictionaries have members whose names are the names of properties from 
Object.prototype.

So I would be OK with changing the rules in #es-dictionary so that null 
and undefined get converted into empty dictionaries.  The trouble though 
is when considering overloading -- I am not sure that I would want null 
or undefined to select an operation whose argument type is a dictionary.

Currently the overload resolution algorithm does not use undefined to 
select object-ish types (interface types, "object", dictionaries, 
array/sequence types).  If undefined could be used to select a 
dictionary type, then I would want to disallow overloading primitive 
types vs dictionary types, such as

   dictionary D { };
   void f(long x);
   void f(D x);

I just realised this same case applies to Lachy's request to allow 
undefined to select nullable non-primitive types in the overload 
resolution algorithm.  On my initial thoughts, I would want to refuse 
that request too, since we already have:

   interface HTMLSelectElement {
     ...
     void add(HTMLOptionElement element, optional HTMLElement? before);
     void add(HTMLOptionElement element, long before);
   };

Well, in this case the proposed "treat undefined as missing optional 
argument" would probably kick in first.

What I am trying to do is to limit the situations where you have two 
distinguishable types, and an ECMAScript value that does not remove one 
or both of these types during the overload resolution.  The only 
situation where this case comes up at the moment is when you consider 
multiple interfaces and an object that happens to implement both:

   void f(Node n);
   void f(EventTarget t);

This is not disallowed in the IDL (per the rules in the Overloading 
section, since Node and EventTarget are "distinguishable"), but you'll 
definitely be able to pass an object in that implements both.  The spec 
says currently just to resolve the tie according to prose, or 
arbitrarily otherwise.  This isn't particularly satisfying, but I can 
live with it.

(Recent changes to the spec limit objects to implementing only one IDL 
interface and all of its inherited/consequential interfaces, so in fact 
I can probably remove that ambiguous case now.)

What I don't want is a case like:

   void f(long x);
   void f(Node n);

where calling f(undefined) does not disambiguate the call.  Currently, 
all other ECMAScript values that you can pass in as the argument will 
either disqualify one or both of those calls.

With respect to null, currently no types (except for "any") include null 
in their sets of values.  You always have to use "?".  I wouldn't want 
to make null select a dictionary type during overload resolution unless 
we disallow "DictionaryType?".  Otherwise passing null to these two 
functions would mean slightly different things:

   void f(DictionaryType d);
   void g(DictionaryType? d);


Here is a proposal then: we define dictionary types not to be 
distinguishable from primitive types.  This would disallow overloading like

   void f(DictionaryType d);
   void f(long x);

avoiding the problem of what undefined selects.  We would leave null out 
of it, so passing null here would disqualify both calls.  You would 
still be allowed to write "DictionaryType?" if your API wanted to 
distinguish between an empty dictionary and the null value for whatever 
reason.

Also, the conversion in #es-dictionary would throw for any value that is 
not an object, null or undefined.

Received on Monday, 22 August 2011 23:24:16 UTC