[whatwg] Adding ECMAScript 5 array extras to HTMLCollection

On Wed, Aug 4, 2010 at 11:10 AM, Alex Russell <slightlyoff at google.com> wrote:
> Sorry for the lagged response,
>
> On Fri, Jul 30, 2010 at 2:56 PM, Oliver Hunt <oliver at apple.com> wrote:
>>
>> On Jul 30, 2010, at 2:46 PM, Alex Russell wrote:
>>
>>> On Fri, Jul 30, 2010 at 4:18 AM, Jonas Sicking <jonas at sicking.cc> wrote:
>>>> On Thu, Jul 29, 2010 at 5:45 PM, Ian Hickson <ian at hixie.ch> wrote:
>>>>>
>>>>> The e-mails quoted below consist of the salient points of this thread:
>>>>>
>>>>> On Fri, 23 Apr 2010, David Bruant wrote:
>>>>>>
>>>>>> Make that HTMLCollection (and all HTML*Collection, as a consequence of
>>>>>> inheritence of HTMLCollection) inherit from the ECMAScript Array
>>>>>> prototype. This way, it will make available all Array extra methods
>>>>>> (forEach, map, filter...) added in ECMAScript5 (and next versions which
>>>>>> should go in the same direction).
>>>>>>
>>>>>> As far as I know, adding this won't break any existing code. The
>>>>>> semantics of a Collection and the way it is used is very close from
>>>>>> ECMAScript Arrays. I don't think that the notion of "live object" and
>>>>>> ECMAScript Array are incompatible either. Once again, I am talking about
>>>>>> ECMAScript binding. I have no intention to touch the HTMLCollection
>>>>>> interface or other languages bindings.
>>>>>
>>>>> On Sun, 25 Apr 2010, J Z wrote:
>>>>>>
>>>>>> If HTMLCollection was inheriting from Array, and methods like `forEach`,
>>>>>> `map`, etc. were to operate on a live object, there would definitely be
>>>>>> undesired consequences. We can see this in, say, Firefox (which allows to
>>>>>> set [[Prototype]] of `HTMLCollection` to `Array.prototype`):
>>>>>>
>>>>>> HTMLCollection.prototype.__proto__ = Array.prototype;
>>>>>>
>>>>>> document.getElementsByTagName('div').forEach(function(el) {
>>>>>> ? el.parentNode.removeChild(el); // doesn't work as expected
>>>>>> });
>>>>>>
>>>>>> // turning live collection into static array fixes this
>>>>>> Array.slice(document.getElementsByTagName('div')).forEach(function(el) {
>>>>>> ? el.parentNode.removeChild(el);
>>>>>> });
>>>>>
>>>>> On Sat, 24 Apr 2010, David Bruant wrote:
>>>>>>
>>>>>> I think I can take your point as a "pro" more than a "con", because in
>>>>>> ES5, right before the definition of each array extra method, a paragraph
>>>>>> like the following can be found :
>>>>>>
>>>>>> "The range of elements processed by forEach is set before the first call
>>>>>> to callbackfn. Elements which are appended to the array after the call
>>>>>> to forEach begins will not be visited by callbackfn. If existing
>>>>>> elements of the array are changed, their value as passed to callback
>>>>>> will be the value at the time forEach visits them; elements that are
>>>>>> deleted after the call to forEach begins and before being visited are
>>>>>> not visited."
>>>>>>
>>>>>> This point is confirmed by every algorithm where the length is "saved"
>>>>>> once for all before the loop and not got from the .length property each
>>>>>> time.
>>>>>
>>>>> On Mon, 26 Apr 2010, Erik Arvidsson wrote:
>>>>>> On Sun, Apr 25, 2010 at 01:07, David Bruant 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.
>>>>>
>>>>> On Mon, 26 Apr 2010, David Flanagan wrote:
>>>>>>
>>>>>> 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.
>>>>>>
>>>>>> Of course, trying to teach programmers when they ought to call toArray()
>>>>>> and when it is not necessary is another matter. ?Perhaps calling the
>>>>>> method snapshot() and focusing on the live vs. static distinction
>>>>>> instead of the fake array vs. true array distinction would invite less
>>>>>> misuse.
>>>>>>
>>>>>> Or we can just leave the DOM as it is and get used to calling the
>>>>>> equivalent of Prototype's $A() function.
>>>>>
>>>>> Before changing something this substantial, I'd like to have implementor
>>>>> feedback regarding what the best way to address this is:
>>>>>
>>>>> ?- somehow make HTMLCollections and NodeLists inherit from Array?
>>>>>
>>>>> ?- define a bunch of feature on HTMLCollections and NodeLists so that
>>>>> ? they're like arrays?
>>>>
>>>> I don't think this makes sense given the immutability of NodeLists.
>>>
>>> Wait...what? Shouldn't some sort of NodeList be mutable? And shouldn't
>>> JS support immutable Arrays? We need to fix both of these APIs, and we
>>> keep heaping back-pressure on JavaScript's Array without any
>>> reasonable resolution because we're not exploring how to make Array
>>> subtypes work as we want them to for all the use cases (like this)
>>> that we care to express.
>>
>> What would you expect a mutable NodeList to be?
>
> A good example would be the result of document.querySelectorAll().

Why couldn't querySelectorAll return a normal Array?

/ Jonas

Received on Wednesday, 4 August 2010 14:40:54 UTC