Re: [whatwg] Adding ECMAScript 5 array extras to HTMLCollection
On Fri, 30 Jul 2010, Jonas Sicking wrote: Before changing something this substantial, I'd like to have implementor feedback regarding what the best way to address this is [...] Given how often this comes up, I think it's worth addressing this. Based on the discussions, it really doesn't seem like this is an area where how to proceed is especially clear. I would like to recommend that browser vendors experiment in this space and report back with concrete experience and suggestions on how to move forward on this. -- Ian Hickson U+1047E)\._.,--,'``.fL http://ln.hixie.ch/ U+263A/, _.. \ _\ ;`._ ,. Things that are impossible just take longer. `._.-(,_..'--(,_..'`-.;.'
Re: [whatwg] Adding ECMAScript 5 array extras to HTMLCollection
On Aug 4, 2010, at 6:26 PM, Garrett Smith wrote: On 8/4/10, Oliver Hunt oli...@apple.com wrote: On Aug 4, 2010, at 3:32 PM, Garrett Smith wrote: On 8/4/10, Garrett Smith dhtmlkitc...@gmail.com wrote: [...] submitButton in form.elements Existing implementations vary on when they use catchalls. I'd like to see standardization for this behavior and codification so that implementations behave similarly -- either use a catchall for a particular type of collection or use a native object. If a catchall is Native object either way, but either with a new ES catchall behavior or with a native ES object, as specified today. Garrett As a question, if the node lists were implemented as catchalls, how would the behaviour differ from current NodeLists? So your only desire is to have NodeLists lose the host object issues? The only change I can see would be the loss of the host object exceptions in the ES spec, but that just puts you in the position of having semantics that match the current host object behavior in those implementations that already allow array functions to operate on host objects. The semantics for native object are defined by ECMA-262. If collection is required to be implemented as a native ECMAScript object, then it would still be considered a host as a native object, would be indistinguishable from other native objects, both internally and externally, and so would not be subject to ES whether or not the xxx method may be applied to a host object loopholes. Thus, [].slice.call( ho ) It sounds like all you want is for the array (and other similar) methods to work on NodeLists, etc but currently some implementations make use of the ES5 text saying the they don't need to support host objects, correct? An ES definition for the type would merely be for the purpose of removing the ability for an implementation to make use of the we don't need to support operation X on host objects? --Oliver
Re: [whatwg] Adding ECMAScript 5 array extras to HTMLCollection
On 8/5/10, Oliver Hunt oli...@apple.com wrote: On Aug 4, 2010, at 6:26 PM, Garrett Smith wrote: On 8/4/10, Oliver Hunt oli...@apple.com wrote: On Aug 4, 2010, at 3:32 PM, Garrett Smith wrote: On 8/4/10, Garrett Smith dhtmlkitc...@gmail.com wrote: [...] submitButton in form.elements Existing implementations vary on when they use catchalls. I'd like to see standardization for this behavior and codification so that implementations behave similarly -- either use a catchall for a particular type of collection or use a native object. If a catchall is Native object either way, but either with a new ES catchall behavior or with a native ES object, as specified today. Garrett As a question, if the node lists were implemented as catchalls, how would the behaviour differ from current NodeLists? I'll tell you, I took another peek at WebIDL and see now getter. The DOM, web IDL, etc should not be specifying how catchalls work; that's an ECMAScript language feature and so it is the job for the ES committee. In particular, WebIDL should not use terminology getter because that may be confused with the ECMAScript language construct of the same name. So your only desire is to have NodeLists lose the host object issues? That isn't very precise; I can't acknowledge that as being correct. In this thread, I want: * NodeList spec'd as native ES object (DOM) * Static Array generics (ES) * Consolidate collections (DOM) to: - allow [[Get]] to return undefined (not require null) - use more specific terminology than integer index (unsigned long) - resolve has checks for collections (DOM and ES) * Array from a NodeList can be guaranteed with [].prototype.slice.call if NodeList is specified as a native ES object in a DOM specification (perhaps WebIDL, as that effort seems to be continuing). * Array Generics, as JavaScriptTM has, for a while, had Array.slice, et al to simplify from Array.prototype.slice.call. This is something that should be done by ES committee. Regarding indexed collections in general, the behavior of an indexed collection should be consolidated where possible. has checks should work as expected and should not fall apart as shown in the article. var form = document.forms[0]; 0 in form; // false in Gecko Array.prototype.indexOf.call(form, form[0]); Firefox: -1 Safari: 0 [...] I have many other desires, none of them having anything to do with this thread or programming at all. [].slice.call( ho ) It sounds like all you want is for the array (and other similar) methods to work on NodeLists, etc but currently some implementations make use of the ES5 text saying the they don't need to support host objects, correct? An ES definition for the type would merely be for the purpose of removing the ability for an implementation to make use of the we don't need to support operation X on host objects? Sorry, but I didn't understand what you meant by the type. I'm not proposing ES remove the text whether or not the xxx method... if that's what you meant. Rather, I'm proposing that NodeList be specified by the DOM ECMAScript bindings to be a native ECMAScript object. That way, it will not be possible for any ES method to discriminate against a host object. Does that answer your question? Are there any criticism or concerns with that proposal? Garrett
Re: [whatwg] Adding ECMAScript 5 array extras to HTMLCollection
On 8/5/10, Garrett Smith dhtmlkitc...@gmail.com wrote: On 8/5/10, Oliver Hunt oli...@apple.com wrote: On Aug 4, 2010, at 6:26 PM, Garrett Smith wrote: On 8/4/10, Oliver Hunt oli...@apple.com wrote: On Aug 4, 2010, at 3:32 PM, Garrett Smith wrote: On 8/4/10, Garrett Smith dhtmlkitc...@gmail.com wrote: [...] [...] I'm not proposing ES remove the text whether or not the xxx method... if that's what you meant. Rather, I'm proposing that NodeList be specified by the DOM ECMAScript bindings to be a native ECMAScript object. That way, it will not be possible for any ES method to discriminate against a host object. Correction: ...to discriminate against those objects. (ES methods ([].concat, et al) would still be able to discriminate against any other host object that is not implemented as a native object). [...] Garrett
Re: [whatwg] Adding ECMAScript 5 array extras to HTMLCollection
Sorry for the lagged response, On Fri, Jul 30, 2010 at 2:56 PM, Oliver Hunt oli...@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 jo...@sicking.cc wrote: On Thu, Jul 29, 2010 at 5:45 PM, Ian Hickson i...@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
Re: [whatwg] Adding ECMAScript 5 array extras to HTMLCollection
On Wed, Aug 4, 2010 at 11:10 AM, Alex Russell slightly...@google.com wrote: Sorry for the lagged response, On Fri, Jul 30, 2010 at 2:56 PM, Oliver Hunt oli...@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 jo...@sicking.cc wrote: On Thu, Jul 29, 2010 at 5:45 PM, Ian Hickson i...@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
Re: [whatwg] Adding ECMAScript 5 array extras to HTMLCollection
On Aug 4, 2010, at 2:40 PM, Jonas Sicking wrote: On Wed, Aug 4, 2010 at 11:10 AM, Alex Russell slightly...@google.com wrote: Sorry for the lagged response, On Fri, Jul 30, 2010 at 2:56 PM, Oliver Hunt oli...@apple.com wrote: On Jul 30, 2010, at 2:46 PM, Alex Russell wrote: 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? I think in principle it could, but it might be too much compat risk to do now. Returning a fully mutable array would also remove the opportunities to cache and reuse the return value, since each result would really need to be distinct if they are mutable. Regards, Maciej
Re: [whatwg] Adding ECMAScript 5 array extras to HTMLCollection
On 8/4/10, Jonas Sicking jo...@sicking.cc wrote: On Wed, Aug 4, 2010 at 11:10 AM, Alex Russell slightly...@google.com wrote: Sorry for the lagged response, On Fri, Jul 30, 2010 at 2:56 PM, Oliver Hunt oli...@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 jo...@sicking.cc wrote: On Thu, Jul 29, 2010 at 5:45 PM, Ian Hickson i...@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: [snip] To all, please trim quotes to a minimum - thanks. 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? It could have done that. It would not be immutable. How much interoperability issue would changing it now cause? Array could be an ECMA binding as a potential consideration as an idea for alternative to non-live static nodelist. Changing live collections to be Arrays would cause severe interoperability problems. It would be very complicated. Then if you're going to get an array, it should be possible to set an array. I suppose in this sort of situation a setItems method could be useful: var cells = Array.prototype.slice.call(row.cells).sort( comparator ); row.childNodes.setItems( cells ); The first line is a bit ugly and so it would be nice to have it a more succinct, not to save typing,
Re: [whatwg] Adding ECMAScript 5 array extras to HTMLCollection
On 8/4/10, Garrett Smith dhtmlkitc...@gmail.com wrote: [...] submitButton in form.elements Existing implementations vary on when they use catchalls. I'd like to see standardization for this behavior and codification so that implementations behave similarly -- either use a catchall for a particular type of collection or use a native object. If a catchall is Native object either way, but either with a new ES catchall behavior or with a native ES object, as specified today. Garrett
Re: [whatwg] Adding ECMAScript 5 array extras to HTMLCollection
On Aug 4, 2010, at 3:32 PM, Garrett Smith wrote: On 8/4/10, Garrett Smith dhtmlkitc...@gmail.com wrote: [...] submitButton in form.elements Existing implementations vary on when they use catchalls. I'd like to see standardization for this behavior and codification so that implementations behave similarly -- either use a catchall for a particular type of collection or use a native object. If a catchall is Native object either way, but either with a new ES catchall behavior or with a native ES object, as specified today. Garrett As a question, if the node lists were implemented as catchalls, how would the behaviour differ from current NodeLists? The only change I can see would be the loss of the host object exceptions in the ES spec, but that just puts you in the position of having semantics that match the current host object behavior in those implementations that already allow array functions to operate on host objects. --Oliver
Re: [whatwg] Adding ECMAScript 5 array extras to HTMLCollection
On 8/4/10, Oliver Hunt oli...@apple.com wrote: On Aug 4, 2010, at 3:32 PM, Garrett Smith wrote: On 8/4/10, Garrett Smith dhtmlkitc...@gmail.com wrote: [...] submitButton in form.elements Existing implementations vary on when they use catchalls. I'd like to see standardization for this behavior and codification so that implementations behave similarly -- either use a catchall for a particular type of collection or use a native object. If a catchall is Native object either way, but either with a new ES catchall behavior or with a native ES object, as specified today. Garrett As a question, if the node lists were implemented as catchalls, how would the behaviour differ from current NodeLists? The externally observable behavior wouldn't have to change. [[HasProperty]] checks (using `in`) with catchalls have sometimes unexpected results, so I wouldn't want to see that kind of change. Try some of the tests here: http://jibbering.com/faq/names/extra_props.html The article needs a little updating but the examples I'm referring to demonstrate disparity with `in` operator: FF3.6 'test' in this.form true 'test' in this.form.elements false A catchall should possible for a result of `null` for indexed access. This probably isn't adding any value over returning `undefined` because many implementations will result `undefined` for property access and most programs won't care one way or the other (and if they do, they're not interoperable with existing browsers). I want the specs to codify behavior of existing various collections and to do that, I want to figure out where and why catchall is used. I can't answer as to why Gecko uses a catchall; perhaps some of the Mozilla devs on this list can give further info. Perhaps there is behavior for past names map that requires catchall (I don't think anybody is a big fan of past names map). The only change I can see would be the loss of the host object exceptions in the ES spec, but that just puts you in the position of having semantics that match the current host object behavior in those implementations that already allow array functions to operate on host objects. The semantics for native object are defined by ECMA-262. If collection is required to be implemented as a native ECMAScript object, then it would still be considered a host as a native object, would be indistinguishable from other native objects, both internally and externally, and so would not be subject to ES whether or not the xxx method may be applied to a host object loopholes. Thus, [].slice.call( ho ) could be expected work. It would have to work because Array.prototype.slice would have no way of determining that `ho` is a host object; it would simply see that it is passed in a native object. It would not be able to differentiate or discriminate between that and a user-defined object. All that would be necessary to make that happen would be to state that the collection -- NodeList, for example -- is implemented as a native ECMAScript object. That alone would be enough to guarantee that any native operation would have results that could be expected. Again, from ES point of view, there are two types of host objects: 1) host object implemented as a native object 2) host object implemented with other semantics Garrett
Re: [whatwg] Adding ECMAScript 5 array extras to HTMLCollection
On 07/30/2010 06:43 AM, Oliver Hunt wrote: all array functions defined in ES5 are generic in that they work over any array-like object. They're guaranteed to work over any array-like native JavaScript object. They're *not* guaranteed to work on host objects like the various node lists. FWIW in practice `Array.prototype.*.call(htmlcollection)` does work on the modern desktop browsers except for IE. It would be possible to specify that the native-JS object guarantee should also extend to node lists. This would allow fast browser implementations of the array-like methods to be used without having to copy to a new Array. However this would still leave the method of calling them a little ugly. -- And Clover mailto:a...@doxdesk.com http://www.doxdesk.com/
Re: [whatwg] Adding ECMAScript 5 array extras to HTMLCollection
On Aug 2, 2010, at 7:36 AM, And Clover wrote: On 07/30/2010 06:43 AM, Oliver Hunt wrote: all array functions defined in ES5 are generic in that they work over any array-like object. They're guaranteed to work over any array-like native JavaScript object. They're *not* guaranteed to work on host objects like the various node lists. Uhhh, I have no idea what you're talking about -- there are no type checks in any of the array prototype functions, they all operate in terms of property access alone, all the methods we're talking about basically start out like this: 1. Let O be the result of calling ToObject passing the this value as the argument. 2. Let lenValue be the result of calling the [[Get]] internal method of O with the argument length. 3. Let len be ToUint32(lenValue). 4. If IsCallable(callbackfn) is false, throw a TypeError exception. 5. If thisArg was supplied, let T be thisArg; else let T be undefined. 6. Let k be 0. 7. Repeat, while k len Eg. array-like in the context of ES5 should be interpreted as has a property named 'length', the array methods will work on any type. FWIW in practice `Array.prototype.*.call(htmlcollection)` does work on the modern desktop browsers except for IE. It would be possible to specify that the native-JS object guarantee should also extend to node lists. This would allow fast browser implementations of the array-like methods to be used without having to copy to a new Array. However this would still leave the method of calling them a little ugly. As above there is no question of it being possible -- the spec behaviour makes no exceptions for host vs. native object types. If IE has a bug, then IE has a bug, that doesn't change the spec. --Oliver
Re: [whatwg] Adding ECMAScript 5 array extras to HTMLCollection
On 8/2/10, Oliver Hunt oli...@apple.com wrote: On Aug 2, 2010, at 7:36 AM, And Clover wrote: On 07/30/2010 06:43 AM, Oliver Hunt wrote: all array functions defined in ES5 are generic in that they work over any array-like object. They're guaranteed to work over any array-like native JavaScript object. They're *not* guaranteed to work on host objects like the various node lists. Uhhh, I have no idea what you're talking about -- there are no type checks in any of the array prototype functions, they all operate in terms of property access alone, all the methods we're talking about basically start out like this: [..] And they continue like this: Whether the [something] function can be applied successfully to a host object is implementation-dependent. Where [something] is replaced by slice in this case. Eg. array-like in the context of ES5 should be interpreted as has a property named 'length', the array methods will work on any type. That is not true. ECMAScript has what is called host object. A host is any ecmascript object that is not defined by the specification; it is not a user-defined object (because that explicitly defined to be a native object). A host object may or may not be implemented as a native ECMAScript object. That leaves two types of host objects: 1) native 2) non-native More on that: https://mail.mozilla.org/pipermail/es-discuss/2010-July/thread.html#11501 Nothing says that any of the various dom collection objects must be native object. The W3C does not define an interface collection; The term itself comes from Microsoft IE 4, which predates the w3c DOM; hence the quotes around the term collection. FWIW in practice `Array.prototype.*.call(htmlcollection)` does work on the modern desktop browsers except for IE. It would be possible to specify that the native-JS object guarantee should also extend to node lists. This would allow fast browser implementations of the array-like methods to be used without having to copy to a new Array. However this would still leave the method of calling them a little ugly. As above there is no question of it being possible -- the spec behaviour makes no exceptions for host vs. native object types. If IE has a bug, then IE has a bug, that doesn't change the spec. IE does not have a bug. IE does not implement its host objects as native ES objects. I proposed to change that by defining an interface that would require that, as well as putting a definition of [[Get]] property access on such objects in one place; not scattered through various interfaces as they currently are and will continue to be otherwise, with the proliferation of new indexed collection type interfaces. Garrett
Re: [whatwg] Adding ECMAScript 5 array extras to HTMLCollection
On Aug 2, 2010, at 12:57 PM, Garrett Smith wrote: I also linked to the old catchalls proposal earlier in the thread. That is because the host objects mentioned here have a specialized catchall behavior that isn't yet defined by any specification, so when the code has property access with an integer index, as: anObj[2] - then it's supposed to be the same as a call to the `item` method. That mostly works, but isn't specified isn't completely and isn't completely interoperable due to variance in undefined vs null. I noticed that rather than define catchall, HTML5 copied the old DOM text: | In the ECMAScript DOM binding, objects implementing the | HTMLFormControlsCollection interface must support being | dereferenced using the square bracket notation, such that dereferencing | with an integer index is equivalent to invoking the item() method with that | index, and such that dereferencing with a string index is equivalent to | invoking the namedItem() method with that index. The problem with that is that property access doesn't do any typechecking, and so obj[2] - is equivalent to:- obj[2] Can it be argued as to what integer index means? And what is a string index? It does seem a little weird as EcmaScript does not distinguish between string and non-string property names, the special handling of numeric indices inside the [[GetOwnProperty]]/[[PutOwnProperty]] methods of those types that have special handling, in those types the special numeric index path is hit if the property name is an Array index, which is defined as (pseudo code) bool isArrayIndex(String property) { unsigned index = ToUint32(property); return ToString(index) == property index = 0 index 0x; } Garrett --Oliver
Re: [whatwg] Adding ECMAScript 5 array extras to HTMLCollection
On Fri, Jul 30, 2010 at 2:46 PM, Alex Russell slightly...@google.com wrote: On Fri, Jul 30, 2010 at 4:18 AM, Jonas Sicking jo...@sicking.cc wrote: On Thu, Jul 29, 2010 at 5:45 PM, Ian Hickson i...@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
Re: [whatwg] Adding ECMAScript 5 array extras to HTMLCollection
On 08/02/2010 09:57 PM, Garrett Smith wrote: Can it be argued as to what integer index means? And what is a string index? Good catch, that's pretty ambiguous language. Browsers implement this as if integer index were equal to the term array index defined section 15.4 of ECMA262 (that is an unsigned 32-bit integer other than (132)-1, expressed in simplest-possible decimal form), and string index meaning any other index. The paragraph should be updated to explicitly reference this; probably the language about square brackets should be dropped too, as it seems to represent a misunderstanding of exactly how the ECMAScript square-bracket and dot operators actually work. Whether a property name is an array index or not is an unrelated issue to the matter of how the property value is retrieved. OK, you can't use the direct dot syntax on an array index purely as a grammatical manner, but . and [] aren't the only way to access properties. (eg. document.links.hasOwnProperty('0').) -- And Clover mailto:a...@doxdesk.com http://www.doxdesk.com/
Re: [whatwg] Adding ECMAScript 5 array extras to HTMLCollection
On 8/2/10, And Clover and...@doxdesk.com wrote: On 08/02/2010 09:57 PM, Garrett Smith wrote: Can it be argued as to what integer index means? And what is a string index? Good catch, that's pretty ambiguous language. Browsers implement this as if integer index were equal to the term array index defined section 15.4 of ECMA262 (that is an unsigned 32-bit integer other than (132)-1, expressed in simplest-possible decimal form), and string index meaning any other index. Not exactly. An array's `length` is 1 greater than the largest index in the array; represented as uint internally. The largest possible array index is 2^32 - 2. ES5 specification says this a bit differently: | A property name P (in the form of a String value) is | an array index if and only if ToString(ToUint32(P)) is | equal to P and ToUint32(P) is not equal to 232-1 That could cover integer index, but the remaining undefined is string index, which seems a paradoxical name, even for Java programmers. Suppose string index could be any other index. Or it could be any index matching production for NAME. But then, does that mean property access on an HTMLCollection can never return undefined? Seems so; must be either `null` or an object. If the a collection is spec'd to use specialized [[Get]] access, then it may need to use catchalls. Again, browsers do use these in some cases and they aren't specified. The paragraph should be updated to explicitly reference this; probably the language about square brackets should be dropped too, as it seems to represent a misunderstanding of exactly how the ECMAScript square-bracket and dot operators actually work. Whether a property name is an array index or not is an unrelated issue Depends. If a specialized [[Get]] implemented as a catchall, then the browsers do some checking. A specialized [[Get]] may be interfering with array generics working with IE host object collections. It may have been that it was too complicated and that the developers decided that it was easier to fail fast by throwing JScript object expected'. Again, on that error, if `ho` is a host object, then the behavior in IE = 8 for `[].slice.call( ho )` is JScript object expected. IE operation sees that the context -- the `this`value -- is not a JScript object and then aborts prematurely, without trying. It could be that the attempt to slice the object could actually succeed, as: - 0 in ho length in ho - is true. to the matter of how the property value is retrieved. OK, you can't use the direct dot syntax on an array index purely as a grammatical manner, but . and [] aren't the only way to access properties. (eg. document.links.hasOwnProperty('0').) That shows that `hasOwnProperty` is present on the object and that calling it returns true where there. For compatibility with IE, a layer of indirection may be used: ({}).hasOwnProperty.call(document.links, 0); - and resulting true in IE. However, that hasOwnProperty check does not always true for collections. As seen in the previous example I posted, for property P, [[HasProperty]] resulted false when there is a property P. Once again, this time with hasOwnProperty, I see a result in Firefox 3.6: [false, object] javascript: var result = [ ({}).hasOwnProperty.call(document.forms[0], 0), typeof document.forms[0][0] ]; alert( result ) HTML5 also codifies a common form memory leak as past names map. Both of those oddities were explained more here: http://www.jibbering.com/faq/names/ However, AFAIK, HTML5 does not specify the catchall behavior for the approach for specialized property access seen there. Does a collection have element properties? (and by element, I do not mean Element, but indexed/keyed item that represents an object in the collection. If it does, then that's a lot easier. Spec'd specialized behavior for property accessors can be removed; as that behavior is already defined by ECMA-262. The only change could be to allow for integer index access to return `undefined`, as it currently does in most browsers. If any collection does not have element properties, then it is necessary to define integer index and string access, at least for that collection. Most collections appear to have element properties and so I can't see any reason for not specifying that. I recall raising discussion of property access on collections over a year ago, before writing the article I've linked above. Garrett
Re: [whatwg] Adding ECMAScript 5 array extras to HTMLCollection
On 8/2/10, Garrett Smith dhtmlkitc...@gmail.com wrote: On 8/2/10, And Clover and...@doxdesk.com wrote: On 08/02/2010 09:57 PM, Garrett Smith wrote: [...] ({}).hasOwnProperty.call(document.links, 0); - and resulting true in IE. However, that hasOwnProperty check does not always true for ...does not always result `true for... collections. As seen in the previous example I posted, for property P, [[HasProperty]] resulted false when there is a property P. Once again, this time with hasOwnProperty, I see a result in Firefox 3.6: [false, object] That was not clear, I meant that [[HasProperty]] resulted false and [[Get]], via property accessors. resulted in the element being retrieved. Garrett
Re: [whatwg] Adding ECMAScript 5 array extras to HTMLCollection
On Thu, Jul 29, 2010 at 5:45 PM, Ian Hickson i...@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. - provide a toArray() method or equivalent? I think this would make sense, though I think it's also worth supplying functions that
Re: [whatwg] Adding ECMAScript 5 array extras to HTMLCollection
On Fri, Jul 30, 2010 at 12:43 AM, Oliver Hunt oli...@apple.com wrote: The various html collections aren't fixed length, they're not assignable, so they can't used interchangeably with arrays at the best of times. Array generics work on arrays that aren't fixed-length, perhaps obviously, and I believe they're still valid over arrays which have had their indexed properties configured to be unwritable as well. As your later example shows, they can be used interchangeably with arrays at exactly the best of times: when wanting to apply a non-mutating extra to one! We've got the array statics in Firefox (Array.forEach, etc.) and it's made the make-collections-be-arrays cries from those working on front-end JS subside dramatically. I think they would probably solve the problem quite effectively, and not require us to be on the lookout for naming collisions between future Array.prototype and HTMLCollection fields. Mike
Re: [whatwg] Adding ECMAScript 5 array extras to HTMLCollection
On 7/29/10, Garrett Smith dhtmlkitc...@gmail.com wrote: On 7/29/10, Ian Hickson i...@hixie.ch wrote: The e-mails quoted below consist of the salient points of this thread: On Fri, 23 Apr 2010, David Bruant wrote: [...] The difficulty is getting the special behavior for [[Get]] which would seem to require some sort of catchall behavior that I linked to earlier and when it comes to [[HasProperty]] checks, that can be complicated (e.g. `0 in document.forms` doesn't work). It was the FORM element where [[HasProperty]] sometimes results false where [[Get]] results in an object: var aForm = document.forms[0]; [typeof aForm[0], 0 in aForm]; Result in FF: object, false [[Get]] access for various collections is defined for each collection and doesn't work consistently as specified.
Re: [whatwg] Adding ECMAScript 5 array extras to HTMLCollection
On Fri, Jul 30, 2010 at 4:18 AM, Jonas Sicking jo...@sicking.cc wrote: On Thu, Jul 29, 2010 at 5:45 PM, Ian Hickson i...@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
Re: [whatwg] Adding ECMAScript 5 array extras to HTMLCollection
On Jul 30, 2010, at 2:46 PM, Alex Russell wrote: On Fri, Jul 30, 2010 at 4:18 AM, Jonas Sicking jo...@sicking.cc wrote: On Thu, Jul 29, 2010 at 5:45 PM, Ian Hickson i...@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.
Re: [whatwg] Adding ECMAScript 5 array extras to HTMLCollection
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? - provide a toArray() method or equivalent? - do nothing? - something else? -- Ian Hickson U+1047E)\._.,--,'``.fL http://ln.hixie.ch/ U+263A/, _.. \ _\
Re: [whatwg] Adding ECMAScript 5 array extras to HTMLCollection
On Mon, Apr 26, 2010 at 10:04 AM, David Flanagan da...@davidflanagan.com wrote: Erik Arvidsson wrote: for (var i = 0, length = collection.length; i length; i++) // instead of: for (var i = 0; i collection.length; i++) Actually, the former is a problem when the nodelist is modified in the loop; it may result in collection[i] being undefined. Even when checking the length in every iteration you can run into problems. If you remove something earlier in the collection you will *miss* one item unless you fix the loop iterator. We should not let these edge cases get in the way of making the DOM collections feel less foreign to JavaScript. -- erik Rather that trying to make DOM collections feel like arrays, how about just giving them a toArray() method? This is pretty terrible. For lack of a way to subtype Arrays in the language, we're going to contort the entire DOM API (again) to do unnatural things? The right answer here is to make an immutable length Array type/trait/interface and just define the various flavors of HTML collection in those terms. Support for doing this needs to be one of TC39's highest priority tasks, and indeed the work on proxies is going to make it possible in Harmony. No need to screw up the DOM any more than it already has been. 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. David
Re: [whatwg] Adding ECMAScript 5 array extras to HTMLCollection
On Jul 29, 2010, at 9:03 PM, Alex Russell wrote: On Mon, Apr 26, 2010 at 10:04 AM, David Flanagan da...@davidflanagan.com wrote: Erik Arvidsson wrote: for (var i = 0, length = collection.length; i length; i++) // instead of: for (var i = 0; i collection.length; i++) Actually, the former is a problem when the nodelist is modified in the loop; it may result in collection[i] being undefined. Even when checking the length in every iteration you can run into problems. If you remove something earlier in the collection you will *miss* one item unless you fix the loop iterator. We should not let these edge cases get in the way of making the DOM collections feel less foreign to JavaScript. -- erik Rather that trying to make DOM collections feel like arrays, how about just giving them a toArray() method? This is pretty terrible. For lack of a way to subtype Arrays in the language, we're going to contort the entire DOM API (again) to do unnatural things? The right answer here is to make an immutable length Array type/trait/interface and just define the various flavors of HTML collection in those terms. The various html collections aren't fixed length, they're not assignable, so they can't used interchangeably with arrays at the best of times. Support for doing this needs to be one of TC39's highest priority tasks, and indeed the work on proxies is going to make it possible in Harmony. No need to screw up the DOM any more than it already has been. I'm not sure how you expect proxies to help here but for the record all array functions defined in ES5 are generic in that they work over any array-like object. So Array.prototype.forEach.apply(myHTMLCollection, function(...){...}) will work. This is obviously not as elegant as might be liked and TC39 is (or at least was) considering putting generic methods onto the Array constructor, eg. Array.forEach(arrayLike, callback) --Oliver
Re: [whatwg] Adding ECMAScript 5 array extras to HTMLCollection
On 7/29/10, Ian Hickson i...@hixie.ch wrote: The e-mails quoted below consist of the salient points of this thread: On Fri, 23 Apr 2010, David Bruant wrote: [...] 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? Again, mutable operations including [[Put]] include reverse, sort, push, pop won't make sense. - define a bunch of feature on HTMLCollections and NodeLists so that they're like arrays? What about StyleSheetList and CSSRuleList and HTMLOptionsCollection, et al? Too generalized and too complicated. For example, the side effects of cssRuleList.reverse() would be complicated and probably pointless. I'd would not even consider trying to write a generalized fallback for that, even if the implementations decided to implement it (I'm, pretty sure they wont). - provide a toArray() method or equivalent? Isn't it duplicate functionality of Array.prototype.slice.call(obj), so long as `obj` is a Native ECMAScript object? Where do you define `toArray`? Do you define an interface with solely a toArray method and then put that on each collection? Or do you instead define a toArray individually for each indexed collection? That's duplicate functionality repeated for each interface. If you're going to do that, defining a toArray on its own interface and define its functionality in one spot would avoid repetition and concomitant problems associated (e.g. shotgun surgery). - do nothing? SImple for implementors and a simple fallback an be provided. Scripts can use Array.prototype.slice.call(obj) where that works and a `for` loop where it doesn't. A problem with that is the various DOM objects are not required to be implemented with native ECMAScript object semantics. - something else? Could create a super interface that, for ES Binding, is required to be a Native ECMAScript object. If you're going to do that, you could define [[Get]] that finds the property as the various `item()` method does. This is partially specified in various places in the DOM, though is not implemented consistently*. Some interfaces that could implement this hypothetical interface (call it IndexedCollection if you like), would be StyleSheetList, CSSRuleList or NodeList or Collection or HTMLFormControlsCollection. That way, there would be good safety from: var sheet = document.styleSheets[0], rules; if(sheet sheet.cssRules) { rules = Array.prototype.slice.call(sheet.cssRules); } The difficulty is getting the special behavior for [[Get]] which would seem to require some sort of catchall behavior that I linked to earlier and when it comes to [[HasProperty]] checks, that can be complicated (e.g. `0 in document.forms` doesn't work). http://wiki.ecmascript.org/doku.php?id=strawman:catchalls * Invoking the `item` method and using property accessor are not equivalent, though different w3c DOM specifications state, in various places: | Note: This object can also be dereferenced using square | bracket notation (e.g. obj[1]). Dereferencing with an integer | index is equivalent to invoking the item method with that index. And we can see that sometimes browsers will return null for `obj.item(888)` and undefined for `obj[888]`. The main ideas of the proposed hypothetical interface are to 1) consolidate that into one place and 2) define that whatever is a collection is a Native ECMAScript Object. -- Garrett
Re: [whatwg] Adding ECMAScript 5 array extras to HTMLCollection (ATTN IE TEAM - TRAVIS LEITHEAD)
On 28/04/10 23:28, Garrett Smith wrote: On Wed, Apr 28, 2010 at 2:12 AM, James Grahamjgra...@opera.com wrote: On 04/28/2010 10:27 AM, David Bruant wrote: When I started this thread, my point was to define a normalized way (through ECMAScript binding) to add array extras to array-like objects in the scope of HTML5 (HTMLCollection and inheriting interfaces). I don't see any reason yet to try to find a solution to problems that are in current web browsers. Of course, if/when a proposal emerges from this thread and some user agent accept to implement it, a workaround (probably, feature detection) will have to be found to use the feature in user agents that implement it and doing something equivalent in web browsers that don't. To be clear the proposals in this thread are pure syntactic sugar; they don't allow you do do anything that you can't already do like: Array.prototype.whatever.call(html_collection, arg1, arg2, ...) where whatever is the array method you are interested in. - and from that you can expect errors in Internet Explorer up to and including version 8. Adding a toArray operation (for example) won't work in IE up to and including version 8 though either. There's no point in adding a toArray operation for the pure reason that they currently don't implement another part of the spec (through the WebIDL references) currently. toArray adds no extra usefulness once they implement other parts of the spec. Of course there is nothing wrong with making the syntax more natural if it can be done in a suitably web-compatible way. However it seems more sensible to do this at a lower level e.g. as part of Web DOM Core. Sadly that spec is in need of an editor. The problem that has been well established is that Internet Explorer's implementation of host object collections or dhtml collection[1] objects is incompatible with JScript implementation of Array generics. The result of attempting to supply an Internet Explorer dhtml collection to an Array generic method, e.g. slice, as the `this` value, results in a jscript runtimer error: JScript object expected. IE8: [].slice.call(document.styleSheets); Result: Error: JScript object expected. In IE8 document.styleSheets.toArray().slice(0, 1); also throws an error. How does adding toArray help for IE8, which you're giving as the reason for adding it? Travis Leithead and IE Team: Can you release Internet Explorer 9 with all dhtml collections implemented as native EcmaScript objects? As far as I am aware, none of them are on this list. -- Geoffrey Sneddon — Opera Software http://gsnedders.com/ http://www.opera.com/
Re: [whatwg] Adding ECMAScript 5 array extras to HTMLCollection (ATTN IE TEAM - TRAVIS LEITHEAD)
On Thu, Apr 29, 2010 at 6:59 AM, Geoffrey Sneddon gsned...@opera.com wrote: On 28/04/10 23:28, Garrett Smith wrote: On Wed, Apr 28, 2010 at 2:12 AM, James Grahamjgra...@opera.com wrote: On 04/28/2010 10:27 AM, David Bruant wrote: When I started this thread, my point was to define a normalized way (through ECMAScript binding) to add array extras to array-like objects in the scope of HTML5 (HTMLCollection and inheriting interfaces). I don't see any reason yet to try to find a solution to problems that are in current web browsers. Of course, if/when a proposal emerges from this thread and some user agent accept to implement it, a workaround (probably, feature detection) will have to be found to use the feature in user agents that implement it and doing something equivalent in web browsers that don't. To be clear the proposals in this thread are pure syntactic sugar; they don't allow you do do anything that you can't already do like: Array.prototype.whatever.call(html_collection, arg1, arg2, ...) where whatever is the array method you are interested in. - and from that you can expect errors in Internet Explorer up to and including version 8. Adding a toArray operation (for example) won't work in IE up to and including version 8 though either. There's no point in adding a toArray operation for the pure reason that they currently don't implement another part of the spec (through the WebIDL references) currently. toArray adds no extra usefulness once they implement other parts of the spec. It's pretty hard to make out what you're getting at here. You the spec to refer to something here that they don't implement. It was also hard to understand your meaning in: | To be clear the proposals in this thread are pure syntactic sugar; | they don't allow you do do anything that you can't already do like: | | Array.prototype.whatever.call(html_collection, arg1, arg2, ...) Array.prototype.slice.call(html_collection) is not something that one cannot already do; it *is* something that can be done, however one cannot expect an Array to be returned from that operation in IE = 8. Whatever it is you meant to convey in that paragraph was lost. If IE dhtml collections are implemented as native ECMAScript objects in IE9, the case for the toArray proposal is weak. The fact that IE implements dhtml collections as unwieldy error-throwing objects poses an obstacle at a fundamental level. That problem needs to be addressed by Microsoft. [...] In IE8 document.styleSheets.toArray().slice(0, 1); also throws an error. How does adding toArray help for IE8, which you're giving as the reason for adding it? What lead you to the assumption that I proposed toArray to address problems in IE8? I would not publish something so ludicrous. Travis Leithead and IE Team: Can you release Internet Explorer 9 with all dhtml collections implemented as native EcmaScript objects? As far as I am aware, none of them are on this list. He subscribes to the w3c-censored lists (dog-and-pony shows), but now that you mention it, I don't see his name showing up here much.
Re: [whatwg] Adding ECMAScript 5 array extras to HTMLCollection (ATTN IE TEAM - TRAVIS LEITHEAD)
On Mon, Apr 26, 2010 at 10:04 AM, David Flanagan da...@davidflanagan.com wrote: Erik Arvidsson wrote: [snip] 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 would solve the OP's problem, but what about other collections like NodeList, StyleSheetList, and CSSStyleDeclaration? An interface that has a toArray() method might be more suitable, as it could be added arbitrarily to other interfaces mentioned already. In any case, the problem is not going to go away in IE6. Nor IE7. Nor IE8. IE9 might change to implement Host object collections as native ECMAScript objects, but even then, then the problems will still need to be addressed in all versions of IE prior. MSIE's implementation of Host objects WRT Array generics is a fundamental and significant and important problem that needs to be addressed. If Internet Explorer's problems with Host objects cannot be fixed, then it would be a nice feature to have a way to get an array from a collection. However, Microsoft should release an IE9 where host object collections are implemented as native ECMAscript objects. If they can do that, the problems would not be an issue. What do you say, Travis Leithead and IE Team? Will you release IE9 with host object implemented as native EcmaScript objects? Garrett
Re: [whatwg] Adding ECMAScript 5 array extras to HTMLCollection (ATTN IE TEAM - TRAVIS LEITHEAD)
Le 28/04/2010 00:03, Garrett Smith a écrit : On Mon, Apr 26, 2010 at 10:04 AM, David Flanagan da...@davidflanagan.com wrote: Erik Arvidsson wrote: [snip] 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 would solve the OP's problem, but what about other collections like NodeList, StyleSheetList, and CSSStyleDeclaration? I am sorry, I don't know what OP stands for. An interface that has a toArray() method might be more suitable, as it could be added arbitrarily to other interfaces mentioned already. I agree with this idea and proposed something in that direction recently : http://lists.whatwg.org/htdig.cgi/whatwg-whatwg.org/2010-April/026057.html In any case, the problem is not going to go away in IE6. Nor IE7. Nor IE8. IE9 might change to implement Host object collections as native ECMAScript objects, but even then, then the problems will still need to be addressed in all versions of IE prior. In this case, what do you refer as the problem ? When I started this thread, my point was to define a normalized way (through ECMAScript binding) to add array extras to array-like objects in the scope of HTML5 (HTMLCollection and inheriting interfaces). I don't see any reason yet to try to find a solution to problems that are in current web browsers. Of course, if/when a proposal emerges from this thread and some user agent accept to implement it, a workaround (probably, feature detection) will have to be found to use the feature in user agents that implement it and doing something equivalent in web browsers that don't. MSIE's implementation of Host objects WRT Array generics is a fundamental and significant and important problem that needs to be addressed. If Internet Explorer's problems with Host objects cannot be fixed, then it would be a nice feature to have a way to get an array from a collection. The idea of getting an Array from a collection came out without IE in mind. If we want to have it in a specification, it has to be a good idea regardless browsers specificities. However, Microsoft should release an IE9 where host object collections are implemented as native ECMAscript objects. If they can do that, the problems would not be an issue. What do you say, Travis Leithead and IE Team? Will you release IE9 with host object implemented as native EcmaScript objects? I have not seen any Travis Leithead or IE Team in the recipients. Is that normal ? David
Re: [whatwg] Adding ECMAScript 5 array extras to HTMLCollection
On 27/04/10 20:23, David Bruant wrote: Le 27/04/2010 03:54, Geoffrey Sneddon a écrit : On 26/04/10 19:50, And Clover wrote: David Flanagan wrote: Rather that trying to make DOM collections feel like arrays, how about just giving them a toArray() method? I like that, as a practical and explicit (JavaScript-specific) 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? HTML5 through WebIDL and its ECMAScript binding already does require this. I can see where interfaces are expected to be exposed ([NamedConstructor]) in the global object, but I don't see where it is said that the prototype of the constructor must be extensible. I don't even see this in the section which is the relevent one in my opinion (Interface prototype object) I have read this version of WebIDL : http://dev.w3.org/2006/webapi/WebIDL/ Section 4.1.1 Interface object: The interface object MUST also have a property named prototype with attributes { DontDelete, ReadOnly } whose value is an object called the interface prototype object. This object provides access to the functions that correspond to the operations defined on the interface, and is described in more detail in section 4.4.3 below. -- Geoffrey Sneddon — Opera Software http://gsnedders.com/ http://www.opera.com/
Re: [whatwg] Adding ECMAScript 5 array extras to HTMLCollection (ATTN IE TEAM - TRAVIS LEITHEAD)
On 04/28/2010 10:27 AM, David Bruant wrote: When I started this thread, my point was to define a normalized way (through ECMAScript binding) to add array extras to array-like objects in the scope of HTML5 (HTMLCollection and inheriting interfaces). I don't see any reason yet to try to find a solution to problems that are in current web browsers. Of course, if/when a proposal emerges from this thread and some user agent accept to implement it, a workaround (probably, feature detection) will have to be found to use the feature in user agents that implement it and doing something equivalent in web browsers that don't. To be clear the proposals in this thread are pure syntactic sugar; they don't allow you do do anything that you can't already do like: Array.prototype.whatever.call(html_collection, arg1, arg2, ...) where whatever is the array method you are interested in. Of course there is nothing wrong with making the syntax more natural if it can be done in a suitably web-compatible way. However it seems more sensible to do this at a lower level e.g. as part of Web DOM Core. Sadly that spec is in need of an editor.
Re: [whatwg] Adding ECMAScript 5 array extras to HTMLCollection (ATTN IE TEAM - TRAVIS LEITHEAD)
On Wed, Apr 28, 2010 at 2:12 AM, James Graham jgra...@opera.com wrote: On 04/28/2010 10:27 AM, David Bruant wrote: When I started this thread, my point was to define a normalized way (through ECMAScript binding) to add array extras to array-like objects in the scope of HTML5 (HTMLCollection and inheriting interfaces). I don't see any reason yet to try to find a solution to problems that are in current web browsers. Of course, if/when a proposal emerges from this thread and some user agent accept to implement it, a workaround (probably, feature detection) will have to be found to use the feature in user agents that implement it and doing something equivalent in web browsers that don't. To be clear the proposals in this thread are pure syntactic sugar; they don't allow you do do anything that you can't already do like: Array.prototype.whatever.call(html_collection, arg1, arg2, ...) where whatever is the array method you are interested in. - and from that you can expect errors in Internet Explorer up to and including version 8. Of course there is nothing wrong with making the syntax more natural if it can be done in a suitably web-compatible way. However it seems more sensible to do this at a lower level e.g. as part of Web DOM Core. Sadly that spec is in need of an editor. The problem that has been well established is that Internet Explorer's implementation of host object collections or dhtml collection[1] objects is incompatible with JScript implementation of Array generics. The result of attempting to supply an Internet Explorer dhtml collection to an Array generic method, e.g. slice, as the `this` value, results in a jscript runtimer error: JScript object expected. IE8: [].slice.call(document.styleSheets); Result: Error: JScript object expected. No other 21st century browsers exhibit such problems, to my knowledge. The problem is with Internet Explorer. A program cannot safely use such constructs without at least feature testing with a try-catch. If Microsoft will release Internet Explorer 9 with dhtml collections implemented as native EcmaScript objects, then your proposal would not be needed and would only add more complexity to the overly complicated WebIDL (which should have been scrapped and restarted). The example would do what is obviously wanted of it and create an array from the StyleSheetList object. I am asking for Microsoft to not Internet Explorer 9 with dhtml collections as unwieldy error-throwing objects. I am asking Microsoft to instead release Internet Explorer 9 with all dhtml collections implemented as native EcmaScript objects. Travis Leithead and IE Team: Can you release Internet Explorer 9 with all dhtml collections implemented as native EcmaScript objects? http://msdn.microsoft.com/en-us/library/ms533048%28VS.85%29.aspx
Re: [whatwg] Adding ECMAScript 5 array extras to HTMLCollection (JZ and David Bruant)
Le 26/04/2010 11:25, Frank Migacz a écrit : What is the implication of denying dynamic changes to the HTMLCollection in a CORS environment? In some variant of Comet (or asynchronous UA polling), how can the UA implement change if it is regularly processing inside locked control blocks? I am not sure I fully understand what you are saying. I don't have the impression that in the code samples we wrote we were locked in any control block. Can you provide more details with your example ? To answer one question (which may not be yours), if a JS code is stuck in a while(1), then, events are never handled. In that situation, XMLHttpRequest events or server-sent events are particular cases of events which won't be handled as well. David
Re: [whatwg] Adding ECMAScript 5 array extras to HTMLCollection
On 26/04/10 19:50, And Clover wrote: David Flanagan wrote: Rather that trying to make DOM collections feel like arrays, how about just giving them a toArray() method? I like that, as a practical and explicit (JavaScript-specific) 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? HTML5 through WebIDL and its ECMAScript binding already does require this. -- Geoffrey Sneddon — Opera Software http://gsnedders.com/ http://www.opera.com/
Re: [whatwg] Adding ECMAScript 5 array extras to HTMLCollection
Le 27/04/2010 03:54, Geoffrey Sneddon a écrit : On 26/04/10 19:50, And Clover wrote: David Flanagan wrote: Rather that trying to make DOM collections feel like arrays, how about just giving them a toArray() method? I like that, as a practical and explicit (JavaScript-specific) 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? HTML5 through WebIDL and its ECMAScript binding already does require this. I can see where interfaces are expected to be exposed ([NamedConstructor]) in the global object, but I don't see where it is said that the prototype of the constructor must be extensible. I don't even see this in the section which is the relevent one in my opinion (Interface prototype object) I have read this version of WebIDL : http://dev.w3.org/2006/webapi/WebIDL/ David
Re: [whatwg] Adding ECMAScript 5 array extras to HTMLCollection
Erik Arvidsson wrote: for (var i = 0, length = collection.length; i length; i++) // instead of: for (var i = 0; i collection.length; i++) Actually, the former is a problem when the nodelist is modified in the loop; it may result in collection[i] being undefined. Even when checking the length in every iteration you can run into problems. If you remove something earlier in the collection you will *miss* one item unless you fix the loop iterator. We should not let these edge cases get in the way of making the DOM collections feel less foreign to JavaScript. -- erik 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. David
Re: [whatwg] Adding ECMAScript 5 array extras to HTMLCollection
On Mon, Apr 26, 2010 at 9:49 AM, Erik Arvidsson a...@chromium.org wrote: On Sun, Apr 25, 2010 at 01:07, David Bruant bru...@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'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.
Re: [whatwg] Adding ECMAScript 5 array extras to HTMLCollection
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. -- erik
Re: [whatwg] Adding ECMAScript 5 array extras to HTMLCollection
David Flanagan wrote: Rather that trying to make DOM collections feel like arrays, how about just giving them a toArray() method? I like that, as a practical and explicit (JavaScript-specific) 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? -- And Clover mailto:a...@doxdesk.com http://www.doxdesk.com/
Re: [whatwg] Adding ECMAScript 5 array extras to HTMLCollection (JZ and David Bruant)
What is the implication of denying dynamic changes to the HTMLCollection in a CORS environment? In some variant of Comet (or asynchronous UA polling), how can the UA implement change if it is regularly processing inside locked control blocks? Please pardon my ignorance of the details. Frank Migacz, Technical Instructor fmig...@gmail.com excerpt: As far as I can see, liveness of HTMLCollection actually does matter. When iterating over HTMLCollection, it's more or less a rule of thumb to save length, to avoid any kind of mismatch (in case code within loop modifies document and so affects length of collection in question): for (var i = 0, length = collection.length; i length; i++) // instead of: for (var i = 0; i collection.length; i++) And another excerpt: For push, I think that : collection.push(document.createTextNode('foo')); // should behave exactly as : collection.childNodes[collection.length] = document.createTextNode('foo'); I don't know what is the current behavior, but if it throws an error, push should throw the same error. If it appends a text node to the body, then push should do the same. sort is a bunch of : tmp = collection[i]; collection[i] = collection[j]; collection[j] = tmp The first instruction is harmless, but if the second one would throw an error, then let's throw the same error for .sort.
Re: [whatwg] Adding ECMAScript 5 array extras to HTMLCollection
Le 26/04/2010 10:33, Garrett Smith a écrit : On Mon, Apr 26, 2010 at 9:49 AM, Erik Arvidssona...@chromium.org wrote: On Sun, Apr 25, 2010 at 01:07, David Bruantbru...@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
Re: [whatwg] Adding ECMAScript 5 array extras to HTMLCollection
On Sat, Apr 24, 2010 at 10:50 PM, J Z kangax@gmail.com wrote: On Fri, Apr 23, 2010 at 10:30 PM, David Bruant bru...@enseirb-matmeca.fr wrote: Hi, In the HTML5 status of this document section, one can read : This specification is intended to replace (be the new version of) what was previously the [...] DOM2 HTML specifications. This spec can be found here : http://www.w3.org/TR/DOM-Level-2-HTML/ It defines ECMAScript language Binding (http://www.w3.org/TR/DOM-Level-2-HTML/ecma-script-binding.html). This document explains how to implement the DOM HTML interfaces in an ECMAScript-compliant environment. Because HTML5 is intended to replace DOM2 HTML, it can freely change ECMAScript bindings. My suggestion is the following : 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. Would the WHATWG have the power to decide something similar regarding NodeList ? Any thoughts ? Thanks, David As far as I can see, liveness of HTMLCollection actually does matter. When iterating over HTMLCollection, it's more or less a rule of thumb to save length, to avoid any kind of mismatch (in case code within loop modifies document and so affects length of collection in question): for (var i = 0, length = collection.length; i length; i++) // instead of: for (var i = 0; i collection.length; i++) Actually, the former is a problem when the nodelist is modified in the loop; it may result in collection[i] being undefined. The reason for storing length can only be to save a few milliseconds in checking it each time i.e. get the length property. 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; Scary. document.getElementsByTagName('div').forEach(function(el) { el.parentNode.removeChild(el); // doesn't work as expected }); Removing a child div of an already removed div seems a bit odd, but whatever. // turning live collection into static array fixes this Array.slice(document.getElementsByTagName('div')).forEach(function(el) { el.parentNode.removeChild(el); }); Where supported, though top level generics such as Array.slice are not standard, so: var divList = document.getElementsByTagName('div'); Array.prototype.slice.call( divList ); Elsewhere: https://mail.mozilla.org/pipermail/es-discuss/2009-December/010241.html
Re: [whatwg] Adding ECMAScript 5 array extras to HTMLCollection
// turning live collection into static array fixes this Array.slice(document.getElementsByTagName('div')).forEach(function(el) { el.parentNode.removeChild(el); }); Where supported, though top level generics such as Array.slice are not standard, so: var divList = document.getElementsByTagName('div'); Array.prototype.slice.call( divList ); Elsewhere: https://mail.mozilla.org/pipermail/es-discuss/2009-December/010241.html Ok. I understand the Array.slice now. Sorry. Array.prototype.slice.call( divList ); is not standard either. In ECMAScript 5, it is stated that : The slice function is intentionally generic; it does not require that its this value be an Array object. Therefore it can be transferred to other kinds of objects for use as a method. Whether the slice function can be applied successfully to a host object is implementation-dependent. Somehow, the reason why I am proposing that HTMLCollections inherit from Array.prototype is to get rid of the implementation-dependant for HTMLCollections which are clearly very good candidates for methods such as forEach, filter (returns a new array (which would be a convinient way to create static copies in one call)) or some/every. David
Re: [whatwg] Adding ECMAScript 5 array extras to HTMLCollection
On Sun, Apr 25, 2010 at 2:33 AM, David Bruant bru...@enseirb-matmeca.frwrote: Le 24/04/2010 22:50, J Z a écrit : On Fri, Apr 23, 2010 at 10:30 PM, David Bruant bru...@enseirb-matmeca.frwrote: Hi, In the HTML5 status of this document section, one can read : This specification is intended to replace (be the new version of) what was previously the [...] DOM2 HTML specifications. This spec can be found here : http://www.w3.org/TR/DOM-Level-2-HTML/ It defines ECMAScript language Binding ( http://www.w3.org/TR/DOM-Level-2-HTML/ecma-script-binding.html). This document explains how to implement the DOM HTML interfaces in an ECMAScript-compliant environment. Because HTML5 is intended to replace DOM2 HTML, it can freely change ECMAScript bindings. My suggestion is the following : 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. Would the WHATWG have the power to decide something similar regarding NodeList ? Any thoughts ? Thanks, David As far as I can see, liveness of HTMLCollection actually does matter. When iterating over HTMLCollection, it's more or less a rule of thumb to save length, to avoid any kind of mismatch (in case code within loop modifies document and so affects length of collection in question): for (var i = 0, length = collection.length; i length; i++) // instead of: for (var i = 0; i collection.length; i++) 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. Oh, perfect :) 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 }); This code doesn't work as expected as the following doesn't either : var divs = document.getElementsByTagName('div'); for(var i=0, l = divs.length ; i l ; i++){ var el = divs[i]; // Due to the live-ness, this might not work as expected el.parentNode.removeChild(el); } This code written as a for-loop behave exactly the same way (in this case) as the .forEach one, so it's as buggy as the forEach one. Sorry, that was a stupid example indeed. It should have been at least something along the lines of: var els = document.getElementsByTagName('span'); for (var i = 0; i els.length; /* can't access length dynamically */ i++) { var spanEl = document.createElement('span'); spanEl.appendChild(document.createTextNode('foo')); document.body.appendChild(spanEl); } My point is that forEach doesn't create more bugs than before, which is what you seem to imply. If it operates on static collection, then I don't see problems either. Adding .forEach and other Array extras wouldn't prevent programmers to remember that they are dealing with a live object even within a .forEach, the same way they are not supposed to forget it with a for-loop. Sure. 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
Re: [whatwg] Adding ECMAScript 5 array extras to HTMLCollection
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) For push, I think that : collection.push(document.createTextNode('foo')); // should behave exactly as : collection.childNodes[collection.length] = document.createTextNode('foo'); I don't know what is the current behavior, but if it throws an error, push should throw the same error. If it appends a text node to the body, then push should do the same. sort is a bunch of : tmp = collection[i]; collection[i] = collection[j]; collection[j] = tmp The first instruction is harmless, but if the second one would throw an error, then let's throw the same error for .sort. The array.prototype methods are actually shortcuts for usual coding patterns. I describe forEach here : http://longtermlaziness.wordpress.com/2010/04/19/array-foreach-introduction/ (by the way, you must be the same Kangax who did the ES5 compat table. Thank you very much for this work.) And I have just described push and sort. Of course, some patterns (like push, pop, sort, reduce...) may not be compatible with the fact that we are dealing with live objects. I think that it is fine. The way those patterns were working (throwing error, doing nothing, creating a new collection item, whatever) should work the same with the shortcuts. There is no reason to change anything from the DOM point of view and behaviors that was happening on the DOM. Just embed the behavior in the shortcut. Once again, I only want to change the ECMAScript language binding, not the DOM interfaces or semantics. Thank you for your answers, David