[whatwg] Adding ECMAScript 5 array extras to HTMLCollection

David Bruant bruant at enseirb-matmeca.fr
Mon Apr 26 21:56:29 PDT 2010


Le 26/04/2010 10:33, Garrett Smith a écrit :
> On Mon, Apr 26, 2010 at 9:49 AM, Erik Arvidsson<arv at chromium.org>  wrote:
>    
>> On Sun, Apr 25, 2010 at 01:07, David Bruant<bruant at enseirb-matmeca.fr>  wrote:
>>      
>>> Le 25/04/2010 00:39, J Z a écrit :
>>>        
>>>> I have thought a lot about weirdnesses that people could think about like
>>>> trying to assign a value to the HTMLCollection (divs[14] = myOtherDiv), but
>>>> once again, it wouldn't be more allowed than it currently is (I have no idea
>>>> of what happens today, but if an error is thrown in a for-loop, it should
>>>> throw an error as well in a call within a forEach).
>>>>          
>>> How would destructive methods like `push` or `sort` behave? Would
>>> `document.body.childNodes.push(document.createTextNode('foo'))` append text
>>> node to a body element? Or would it be a noop?
>>>
>>> That is actually a very good point.
>>> It think that the behavior should be exactly the same as "an equivalent
>>> without array methods". (this point of my proposal would need to be made
>>> completly explicit for each method)
>>>        
>> One way to solve this could be to split Array into two interfaces. One
>> to be used with immutable array like objects and one to use to mutate
>> objects. Then we could apply the immutable array like interface to
>> NodeList and its related interfaces. The benefit of doing that is that
>> NodeList.prototype.push would be undefined instead of failing when
>> called.
>>      
> Yes, that was also discussed on es-discuss list.
>
> The complaints that have been mentioned on this thread are also detailed:
> https://mail.mozilla.org/pipermail/es-discuss/2009-May/009300.html
> https://mail.mozilla.org/pipermail/es-discuss/2009-May/009323.html
>
> - and the reply by Allen:
> https://mail.mozilla.org/pipermail/es-discuss/2009-May/009323.html
>    
I assume you meant :
https://mail.mozilla.org/pipermail/es-discuss/2009-May/009355.html
> | I'm probably repeating myself here, but an new interface is not
> | necessary to make this requirement explicit.  If you want (and
> | can get agreement) for these objects to fully implement
> | ECMAScript native object semantics then that is all you have to
> | say in the WebIDL JavaScript binding specification.
>
> Nobody argued with that post, which concluded the thread.
>    
I assume Allen Wirfs-Brock meant "implement ECMAScript native object 
semantics" ... as host objects. And I agree with this idea or would 
suggest to say what we have to say either in the WebIDL ECMAScript 
binding or an independent rewriting of the DOM HTML ES binding.

In one of the email you refer to, you said :
 >Host objects currently behave in implementation-dependent manner.
 >Nobody likes it, but that's the way it is. I do not think such
 >"implementation dependent" behavior should be arbitrary.

In my opinion, it's the role of the ECMAScript binding specification to 
determine what is implementation-dependent and what is not. Role that 
previous specifications didn't fill, allowing web browsers to choose, 
thus leading authors to do feature detection or browser sniffing.

I realize now that there is actually a lot that has never been said 
about ECMAScript bindings. WebIDL seems to be a good start. I will have 
a closer look at it.


Back to the main subject, I find interesting the idea of defining 
immutable arrays. To be more precise in the proposal, I would first 
suggest the following :
An *ImmutableCollection* constructor with a prototype containing the 
following methods :
* join
* slice (btw, .slice(0) would return an Array which is a static copy of 
the HTMLCollection)
* splice
* indexOf/lastIndexOf
* every/some
* forEach
* map
* filter
* reduce/reduceRight

Basically, it's all methods where no [[defineOwnProperty]] is used 
directly or indirectly (like through [[put]]).

The definition of each method is strictly the same definition than the 
corresponding method in Array.prototype.

Having this constructor and imposing that HTMLCollections inherit from 
it would make that it is not implementation-dependent anymore.

For the moment, this constructor would be created only for the 
ECMAScript binding purpose.

It would avoid to define methods which, we know, would systematically fail.

> Rather that trying to make DOM collections feel like arrays, how about just
> >  giving them a toArray() method?  This makes it clear that a collection is
> >  not an array, but clearly defines a way to obtain an array.  Clever
> >  implementors might even be able to optimize common uses-cases using some
> >  kind of copy-on-write strategy so that toArray() doesn't involve memory
> >  allocation and copying.
>    
> That might be better than nothing but why should a NodeList not have a
> forEach method? It is pretty clear that people want to be able to
> treat Arguments and NodeList as Arrays.
>    
With my aforementionned proposal. HTMLCollections would have direclty a 
forEach method.

About the idea of clearly defining a way to obtain an Array (for its 
staticness), a method could be added, but no to 
ImmutableCollection.prototype.
Another constructor and prototype would be needed to deal with live 
(dynamic) objects.
Maybe this constructor could be :
*LiveCollection* with method(s) :
* toStaticArray (I think that expliciting "static" is a good thing. It 
can be discussed)

I have tried to separate the notion of "immutable" and "live/dynamic", 
because these are different concepts. It makes sense to say that live 
implies immutable, but the contrary is not obvious. I have not 
investigated, but I know that NodeLists returned by querySelectorAll are 
not live. I think that they are likely to be immutable (it would make 
sense in my opinion).
I don't know any example for HTMLCollection. I'd be interested to know 
if there is any.


For the moment, NodeList are out of the scope of this proposal since 
NodeList is out of the scope of HTML5 (NodeList is defined in DOM core 
level 3 as well as its ES binding).


> In the longer term, what's the thinking on a more basic change:
>
> - Require specific DOM interfaces like NodeList, HTMLCollection, 
> Element etc. to be available for prototype monkey-patching under their 
> interface names as properties of `window`?
>
> Then we wouldn't have to worry about what Array-like methods need to 
> be provided on HTMLCollection, because application and framework 
> authors could choose whichever they liked to prototype in.
>
> IE8/Moz/Op/Saf/Chr already do this to a significant extent, but 
> there's no standard that says they have to. It would allow DOM 
> extension to be put on a much less shaky footing than the messy hack 
> Prototype 1.x uses.
>
> Is this something that's a reasonable requirement for browsers in future? 
There are a lot of examples where adding or modifying an 
object/prototype you don't own ended to be harmful :
http://www.nczonline.net/blog/2010/03/02/maintainable-javascript-dont-modify-objects-you-down-own/
http://perfectionkills.com/whats-wrong-with-extending-the-dom/

As such, my first reaction is to be cautious about this.
For instance, if authors decide to do the following : 
HTMLCollection.prototype.filter = Array.prototype.filter;
Then the filter method on HTMLCollection is expected to return an Array.
If some day, the W3C or WHATWG decides that HTMLCollection are freely 
instanciable (var hcol = new HTMLCollection()) and contain a filter 
methods that MUST return an HTMLCollection, then calls to .filter will 
break because Array and HTMLCollection are different.

Defining in the ES binding what methods the HTMLCollection implements in 
ES has the advantage of making sure that the same method will always 
have the same behavior.
If some day, the W3C or WHATWG decides that HTMLCollection are freely 
instanciable (var hcol = new HTMLCollection()) and contain a filter 
methods that MUST return an HTMLCollection, then in the ES binding, it 
can be decided that the ES method that implements the HTMLCollection 
interface filter method can be called .filterCollection.
This decision won't break any existing code.

David


More information about the whatwg mailing list