Re: Distinguishing objects and arrays?

On 18/09/11 7:57 AM, Anne van Kesteren wrote:
> For the DOM we have this idea of having a method that can conveniently
> create an element, set its attributes, event handlers, and child nodes.
> However, to keep the method convenient some of those need to become
> optional and therefore it requires some kind of overloading, which is
> where things become problematic.
>
> Maybe there is a better design, but so far we have something like this:
>
> create(name)
> create(name, attributes)
> create(name, children)
> create(name, attributes, children)
> create(name, attributes, eventhandlers, children)
>
> name is a string.
>
> attributes is an object.
>
> eventhandlers is an object.
>
> children is either a Node or string, or an array of Nodes and strings.
>
> Examples:
>
> create('h1', 'Welcome!')
> create('button', {name: 'command', value: 'search'}, {onclick: teehee},
> 'Search')
> create('p', {title: 'hi'}, [node, node2])
>
> The problem is however that arrays and objects are not really
> distinguishable unless you do "evil things".
>
> Anyone with ideas?

First, there's no way in Web IDL currently to support the attributes 
argument you have above, unless you write

   Node create(DOMString name, object attributes)

and then in prose dig into the JS properties of the object passed in. 
This may or not be in good taste.  If we want to support it, we should 
introduce a type that is like an open ended dictionary, e.g.

   Node create(DOMString name, dictionary<DOMString> attributes);

Let me know if you are still pursuing an API like the above so I know 
whether to consider something like dictionary<DOMString>.

But to your main question, you are correct that you can't write:

   void f(Node x);
   void f(DOMString x);
   void f(sequence<Node or DOMString> xs);

(to use your proposed union type syntax) since interface types (like 
Node) aren't distinguishable from sequence types.

I think one of the advantages of the way sequence<T> is treated 
currently is that it can take not only a JS Array object, but any object 
at all, since it will just look up a "length" property and then any 
array index properties.  This is handy because array-like non-Array 
objects like NodeList can be passed to the function without having to 
allow it explicitly in the IDL.

So far in the overload resolution algorithm I have avoided making any 
two object-like types distinguishable unless it is solely on the basis 
of which interface they implement.  Now you could just say "if it has a 
length property, choose the sequence one", but then if you wrote

   void g(NodeList x);
   void g(sequence<Node> xs);

we have another one of those situations where a value can plausibly be 
considered to match more than one overload.  Remember that we have this 
problem already with interfaces (technically, if not in practice):

   void h(InterfaceA x);
   void h(InterfaceB x);

What happens when an object that implements both interfaces is passed 
in?  We currently have in the spec that we just choose the first one. 
We could do the same for NodeList vs sequence<Node>.  We might have to 
resolve the "overload resolution consistency" thread to see whether it 
makes sense to do this.

Received on Wednesday, 14 December 2011 04:00:58 UTC