Re: What type should .findAll return
On Nov 12, 2011, at 12:07 PM, Yehuda Katz wrote: Yehuda Katz (ph) 718.877.1325 On Sat, Nov 12, 2011 at 11:51 AM, Allen Wirfs-Brock al...@wirfs-brock.com wrote: On Nov 12, 2011, at 10:27 AM, Boris Zbarsky wrote: On 11/13/11 6:10 AM, Allen Wirfs-Brock wrote: I think you're drawing a distinction between language level semantics and library routine behavior which is for practical purposes irrelevant to everyone outside the ES5 committee... It's relevant to this discussion because you have to decide what web developers actually mean when they say Array. The starting point was that you want NodeArray to be something more than just an Array. So you have do look at all aspects of Array behavior and decide which you care about. The language semantic vs library behavior is relevant because it is often much easer for engine implementers to change or extend library behavior then it is to extend language semantics. In practice, at the moment, if you want something that needs to act like an array as far as a web developer is concerned, it's [[Class]] better be Array. In the future, as you note, that might change. The most important point is that [[Class]] is neither the only nor the most important distinguishing characteristic of ECMAScript built-in Arrays. If you are just arguing about [[Class]] you are missing the point. I think it's worth noting that [[Class]] is actually used by jQuery and other implementations to identify whether an object is a real Array. It may be the case that we could revisit some of those cases, but the technique of using [[Class]] to get a less buggy picture of what an object is (compared to typeof etc.) is pretty common. We use it in SproutCore as well. The jQuery.type function: https://github.com/jquery/jquery/blob/master/src/core.js#L491-495 The class2type map: https://github.com/jquery/jquery/blob/master/src/core.js#L877-879 toString in that function is declared above as Object.prototype.toString. That said, of course other aspects of the observed behavior, such as its exposed methods, matter as well. Those functions are not using [[Class]]. They are using the standard built-in Object.prototype.toString method. Now, it so happens that the specification of toString makes use of [[Class]] but that is simply an artifact of the ES5.1 specification. It is not a language features. The technique that is used to specify toString can be changed without changing the actual behavior of the toString method. All that is really required that existing ES code that depends upon the ES5.1 toString behavior will continue to work without modification in future ES implementations that may use a different specification for toString. However, it doesn'tconstrain future code that operates upon new kinds of objects that didn't exist in the ES5.1 specification. BTW, when the ES5.1 spec. talks about objects whose [[Class]] has a specific value. it means precisely such objects as actually specified in the ES5.1 spec. [[Class]] is not an implementation extension point. In particular, ES5.1 clause 8.6.2 says: The value of the [[Class]] internal property of a host object may be any String value except one of Arguments, Array,... In other words, host object provides (such as a DOM implementation) are not allowed to define new kinds of objects whose [[Class]] is Array. It's fine to want to define a new kind of host object that is behaviorally very similar (but slight different) from instances of the built-in Array constructor. But characterizing such objects by saying they have [[Class]]==Array is a not meaningful from a ES5.1 specification perspective. Allen
Re: What type should .findAll return
[snip] ES5.1 clause 8.6.2 says: The value of the [[Class]] internal property of a host object may be any String value except one of Arguments, Array,... In other words, host object provides (such as a DOM implementation) are not allowed to define new kinds of objects whose [[Class]] is Array. It's fine to want to define a new kind of host object that is behaviorally very similar (but slight different) from instances of the built-in Array constructor. But characterizing such objects by saying they have [[Class]]==Array is a not meaningful from a ES5.1 specification perspective. I'm fine with any formulation, as long as it gives the correct behaviour in cases like Array.prototype.concat and Array.isArray. ES 5.1 15.4.3.2 Array.isArray() ... 2. If the value of the [[Class]] internal property of arg is Array, then return true. ... Considering Allen's previous comment, this is not going to be allowed. Rick Do you have suggestions for what to write? / Jonas
Re: What type should .findAll return
It seems as though the spec intends to disallow host objects (i.e. DOM) from fully acting like an Array, which is clearly the intent here. Perhaps this is a time for willful disobedience and a correction in ES6? Yehuda Katz (ph) 718.877.1325 On Mon, Nov 14, 2011 at 10:46 AM, Rick Waldron waldron.r...@gmail.comwrote: [snip] ES5.1 clause 8.6.2 says: The value of the [[Class]] internal property of a host object may be any String value except one of Arguments, Array,... In other words, host object provides (such as a DOM implementation) are not allowed to define new kinds of objects whose [[Class]] is Array. It's fine to want to define a new kind of host object that is behaviorally very similar (but slight different) from instances of the built-in Array constructor. But characterizing such objects by saying they have [[Class]]==Array is a not meaningful from a ES5.1 specification perspective. I'm fine with any formulation, as long as it gives the correct behaviour in cases like Array.prototype.concat and Array.isArray. ES 5.1 15.4.3.2 Array.isArray() ... 2. If the value of the [[Class]] internal property of arg is Array, then return true. ... Considering Allen's previous comment, this is not going to be allowed. Rick Do you have suggestions for what to write? / Jonas
Re: What type should .findAll return
On Nov 14, 2011, at 3:13 PM, Yehuda Katz wrote: It seems as though the spec intends to disallow host objects (i.e. DOM) from fully acting like an Array, which is clearly the intent here. Perhaps this is a time for willful disobedience and a correction in ES6? Calm down -- this confrontational style is unjustified. The spec cannot deal in non-observables. DOM host objects in most implementations are full of methods, which really are native function objects. But it's always possible to implement a work-alike. So long as a host array follows the contract in every observable way, no problem. What's at issue is the abuse of internal methods defined only for spec-internal purposes as arbitrary plugin APIs by other specs. That's where negotiation and future-proofing are needed. /be Yehuda Katz (ph) 718.877.1325 On Mon, Nov 14, 2011 at 10:46 AM, Rick Waldron waldron.r...@gmail.com wrote: [snip] ES5.1 clause 8.6.2 says: The value of the [[Class]] internal property of a host object may be any String value except one of Arguments, Array,... In other words, host object provides (such as a DOM implementation) are not allowed to define new kinds of objects whose [[Class]] is Array. It's fine to want to define a new kind of host object that is behaviorally very similar (but slight different) from instances of the built-in Array constructor. But characterizing such objects by saying they have [[Class]]==Array is a not meaningful from a ES5.1 specification perspective. I'm fine with any formulation, as long as it gives the correct behaviour in cases like Array.prototype.concat and Array.isArray. ES 5.1 15.4.3.2 Array.isArray() ... 2. If the value of the [[Class]] internal property of arg is Array, then return true. ... Considering Allen's previous comment, this is not going to be allowed. Rick Do you have suggestions for what to write? / Jonas
Re: What type should .findAll return
Sorry, I was making a joke (referencing 1.5.2 of the HTML5 spec), not intending to be confrontational. The underlying issue here is just making it possible for Array.isArray to return true for an Array of DOM nodes that is also enhanced with extra features. Jonas had specifically said that he wanted isArray to work. Rick then pointed out that the spec seems to disallow host objects from claiming that their [[Class]] is Array, and that isArray specifically requires that [[Class]] be Array. I apologize again for my in-jest comment. Yehuda Katz (ph) 718.877.1325 On Mon, Nov 14, 2011 at 3:23 PM, Brendan Eich bren...@mozilla.org wrote: On Nov 14, 2011, at 3:13 PM, Yehuda Katz wrote: It seems as though the spec intends to disallow host objects (i.e. DOM) from fully acting like an Array, which is clearly the intent here. Perhaps this is a time for willful disobedience and a correction in ES6? Calm down -- this confrontational style is unjustified. The spec cannot deal in non-observables. DOM host objects in most implementations are full of methods, which really are native function objects. But it's always possible to implement a work-alike. So long as a host array follows the contract in every observable way, no problem. What's at issue is the abuse of internal methods defined only for spec-internal purposes as arbitrary plugin APIs by other specs. That's where negotiation and future-proofing are needed. /be Yehuda Katz (ph) 718.877.1325 On Mon, Nov 14, 2011 at 10:46 AM, Rick Waldron waldron.r...@gmail.comwrote: [snip] ES5.1 clause 8.6.2 says: The value of the [[Class]] internal property of a host object may be any String value except one of Arguments, Array,... In other words, host object provides (such as a DOM implementation) are not allowed to define new kinds of objects whose [[Class]] is Array. It's fine to want to define a new kind of host object that is behaviorally very similar (but slight different) from instances of the built-in Array constructor. But characterizing such objects by saying they have [[Class]]==Array is a not meaningful from a ES5.1 specification perspective. I'm fine with any formulation, as long as it gives the correct behaviour in cases like Array.prototype.concat and Array.isArray. ES 5.1 15.4.3.2 Array.isArray() ... 2. If the value of the [[Class]] internal property of arg is Array, then return true. ... Considering Allen's previous comment, this is not going to be allowed. Rick Do you have suggestions for what to write? / Jonas
Re: What type should .findAll return
On Nov 14, 2011, at 3:32 PM, Yehuda Katz wrote: Sorry, I was making a joke (referencing 1.5.2 of the HTML5 spec), not intending to be confrontational. Ah, I get it -- indeed such deviations were one of the reasons for creating public-script-coord. SO I get it but I didn't lul. :-| The underlying issue here is just making it possible for Array.isArray to return true for an Array of DOM nodes that is also enhanced with extra features. Jonas had specifically said that he wanted isArray to work. Rick then pointed out that the spec seems to disallow host objects from claiming that their [[Class]] is Array, and that isArray specifically requires that [[Class]] be Array. We need to get this right in the future. It's a tricky issue. But even now I would say that if there's no observable difference, there is no problem. Allen should weigh in. /be I apologize again for my in-jest comment. Yehuda Katz (ph) 718.877.1325 On Mon, Nov 14, 2011 at 3:23 PM, Brendan Eich bren...@mozilla.org wrote: On Nov 14, 2011, at 3:13 PM, Yehuda Katz wrote: It seems as though the spec intends to disallow host objects (i.e. DOM) from fully acting like an Array, which is clearly the intent here. Perhaps this is a time for willful disobedience and a correction in ES6? Calm down -- this confrontational style is unjustified. The spec cannot deal in non-observables. DOM host objects in most implementations are full of methods, which really are native function objects. But it's always possible to implement a work-alike. So long as a host array follows the contract in every observable way, no problem. What's at issue is the abuse of internal methods defined only for spec-internal purposes as arbitrary plugin APIs by other specs. That's where negotiation and future-proofing are needed. /be Yehuda Katz (ph) 718.877.1325 On Mon, Nov 14, 2011 at 10:46 AM, Rick Waldron waldron.r...@gmail.com wrote: [snip] ES5.1 clause 8.6.2 says: The value of the [[Class]] internal property of a host object may be any String value except one of Arguments, Array,... In other words, host object provides (such as a DOM implementation) are not allowed to define new kinds of objects whose [[Class]] is Array. It's fine to want to define a new kind of host object that is behaviorally very similar (but slight different) from instances of the built-in Array constructor. But characterizing such objects by saying they have [[Class]]==Array is a not meaningful from a ES5.1 specification perspective. I'm fine with any formulation, as long as it gives the correct behaviour in cases like Array.prototype.concat and Array.isArray. ES 5.1 15.4.3.2 Array.isArray() ... 2. If the value of the [[Class]] internal property of arg is Array, then return true. ... Considering Allen's previous comment, this is not going to be allowed. Rick Do you have suggestions for what to write? / Jonas
Re: What type should .findAll return
Yehuda Katz (ph) 718.877.1325 On Mon, Nov 14, 2011 at 3:49 PM, Brendan Eich bren...@mozilla.org wrote: On Nov 14, 2011, at 3:32 PM, Yehuda Katz wrote: Sorry, I was making a joke (referencing 1.5.2 of the HTML5 spec), not intending to be confrontational. Ah, I get it -- indeed such deviations were one of the reasons for creating public-script-coord. SO I get it but I didn't lul. :-| The underlying issue here is just making it possible for Array.isArray to return true for an Array of DOM nodes that is also enhanced with extra features. Jonas had specifically said that he wanted isArray to work. Rick then pointed out that the spec seems to disallow host objects from claiming that their [[Class]] is Array, and that isArray specifically requires that [[Class]] be Array. We need to get this right in the future. It's a tricky issue. But even now I would say that if there's no observable difference, there is no problem. Allen should weigh in. One observable difference between this object and an Array (at least under Jonas' proposal) would be that: Object.getPrototypeOf(Object.getPrototypeOf(arrayOfNodes)) would be the inserted DOM list prototype, while Object.getPrototypeOf(Object.getPrototypeOf(regularArray)) would be Object.prototype It would be possible to mask this behavior, but masking it and also making it possible to extend the DOM list prototype would be weird, no? /be I apologize again for my in-jest comment. Yehuda Katz (ph) 718.877.1325 On Mon, Nov 14, 2011 at 3:23 PM, Brendan Eich bren...@mozilla.org wrote: On Nov 14, 2011, at 3:13 PM, Yehuda Katz wrote: It seems as though the spec intends to disallow host objects (i.e. DOM) from fully acting like an Array, which is clearly the intent here. Perhaps this is a time for willful disobedience and a correction in ES6? Calm down -- this confrontational style is unjustified. The spec cannot deal in non-observables. DOM host objects in most implementations are full of methods, which really are native function objects. But it's always possible to implement a work-alike. So long as a host array follows the contract in every observable way, no problem. What's at issue is the abuse of internal methods defined only for spec-internal purposes as arbitrary plugin APIs by other specs. That's where negotiation and future-proofing are needed. /be Yehuda Katz (ph) 718.877.1325 On Mon, Nov 14, 2011 at 10:46 AM, Rick Waldron waldron.r...@gmail.comwrote: [snip] ES5.1 clause 8.6.2 says: The value of the [[Class]] internal property of a host object may be any String value except one of Arguments, Array,... In other words, host object provides (such as a DOM implementation) are not allowed to define new kinds of objects whose [[Class]] is Array. It's fine to want to define a new kind of host object that is behaviorally very similar (but slight different) from instances of the built-in Array constructor. But characterizing such objects by saying they have [[Class]]==Array is a not meaningful from a ES5.1 specification perspective. I'm fine with any formulation, as long as it gives the correct behaviour in cases like Array.prototype.concat and Array.isArray. ES 5.1 15.4.3.2 Array.isArray() ... 2. If the value of the [[Class]] internal property of arg is Array, then return true. ... Considering Allen's previous comment, this is not going to be allowed. Rick Do you have suggestions for what to write? / Jonas
Re: What type should .findAll return
On Nov 14, 2011, at 3:32 PM, Yehuda Katz wrote: Sorry, I was making a joke (referencing 1.5.2 of the HTML5 spec), not intending to be confrontational. The underlying issue here is just making it possible for Array.isArray to return true for an Array of DOM nodes that is also enhanced with extra features. Jonas had specifically said that he wanted isArray to work. Rick then pointed out that the spec seems to disallow host objects from claiming that their [[Class]] is Array, and that isArray specifically requires that [[Class]] be Array. Ultimate you have to decide what it is you are asking for. It been stated that you (DOM API designers) want this kind of object to be a real ECMAScript Array. But you also want to deviate from some aspects of what it currently means to be an a real ECMAScript array. A real ECMAscript Array has a specific [[Prototype]] value. It also has specific behaviors for methods like concat and filter and other specific distinguishing behavioral characteristics all of which are defined in the ES5.1 spec. If you change any of those for some object, it is something other than a real ECMAScript Array. Array.isArray was introduced into ES5 to provide an API for testing whether or not an object actually was a real ECMAScript Array as defined by section 15.4 of the ES5 spec. If Array.isArray starts answering true for objects that aren't described by 15.4 then it ls no longer useful for its intended purpose. The language in 8.6.2 limiting host object use of certain class values is to ensure that host objects can't define things that violate important invariant about the inner workings of ECMAScript. Nobody is saying that it isn't useful to define new objects (host or otherwise) that share some (but not all) of the characteristics of ECMAScript Arrays. However, such object's aren't just ECMAScript array as defined by 15.4 so don't expect Array.isArray to work for them. Perhaps other discriminators are needed but we will all need to decide which specific subset of Array characteristics we want to discriminate. TC39 recognizes that ES needs better support for defining collections, including variants of Array. This includes supporting both better collections defined in ES code and via host objects (in general, TC39 don't like designs that depend uopn a host object being able to do something that can't be done only using ES code). We have features to support better collection definition in advanced stages of design for ES6. Some of these features might be accelerated into implementation ahead of the completion of ES6. However, I'm not sure you would want to normatively specify a DOM feature that depended upon them. Maybe you could... For right now, there are two ways you could quickly go that don't conflict with ES5.1 at all: 1) you can specify that .findAll returns a plain vanilla ECMAScript Array object. 2) you can define a new kind of host object that is a close approximation of a real ECMAScript Array object. Such an object could indirectly inherit from Array.prototype, over-ride some inherited methods (such as concat and filter), and define additional DOM related methods. However, its [[Class]] may not be Array and anything in the ES spec that requires [[Class]]===Array (such as Array.isArray) won't recognize it as an anything special. We can work together on something between these two extremes but the further away from them we go the more we get into the land of ES6 features and the problem of how to advance them into current engines. Allen
RE: What type should .findAll return
From: Allen Wirfs-Brock [mailto:al...@wirfs-brock.com] Sent: Monday, November 14, 2011 6:12 PM For right now, there are two ways you could quickly go that don't conflict with ES5.1 at all: 1) you can specify that .findAll returns a plain vanilla ECMAScript Array object. 2) you can define a new kind of host object that is a close approximation of a real ECMAScript Array object. Such an object could indirectly inherit from Array.prototype, over-ride some inherited methods (such as concat and filter), and define additional DOM related methods. However, its [[Class]] may not be Array and anything in the ES spec that requires [[Class]]===Array (such as Array.isArray) won't recognize it as an anything special. This might be my simplified view of things, but have we just circled back around to the two definitions that Cameron already has in WebIDL [1]? * 3.9.18 Sequences - sequenceT are the corollary of #1 above (plain-old JS arrays) * 3.9.19 Arrays - T[] are the corollary of #2 above; array-like and even are participate in the Array.prototype chain. In section 4.2.20, the following note outlines the difference between the so-called platform array object and a vanilla JS array: Note Platform array objects differ from Array objects in the following ways: - they are never sparse - their elements are always data properties - an ECMAScript-to-IDL value conversion is always performed when storing an element - their internal [[Class]] property value is different - their internal [[Extensible]] property value is always true Can we pick one of these as a starting point for .find()/.findAll()? For consistency with other DOM APIs, I personally see the platform array object as the way forward. [1] http://dev.w3.org/2006/webapi/WebIDL/#idl-sequence
Re: What type should .findAll return
I'd like to see this thing smell like a normal Array, plus useful node methods: 1. It should have at least all of the non-mutating Array methods on it. Possibly the mutating methods too if we allow the returned object to be mutable. Agreed. 2. It should have a object on the prototype chain where we can insert functions that are specifically useful for lists of nodes. Examples include .find/.findAll/.matchesSelector/.remove/.addEventListener It would be nice if it also had getElementsBy*. This object (ElementList?) could be a beachhead allowing us to add more useful functionality to lists of elements in the browser over time. Since this is a totally new API, we're also not bound by the API for individual nodes, so we could use shorter names, like .is() for matchesSelector() and .on() for addEventListener. 3. It would be good if it had the Array prototype object on it's prototype chain so that if Array.prototype was extended, it would affect this object too. Absolutely. 4. The object will *not* be live since live results from selector matching is slow. Agreed. Yehuda Katz (ph) 718.877.1325 On Fri, Nov 11, 2011 at 6:04 PM, Jonas Sicking jo...@sicking.cc wrote: On Fri, Nov 11, 2011 at 5:59 PM, Tab Atkins Jr. jackalm...@gmail.com wrote: On Fri, Nov 11, 2011 at 5:52 PM, Rick Waldron waldron.r...@gmail.com wrote: Right, but I'm saying: why create yet more stuff in the DOM? findAll will return a NodeArray while querySelectorAll and friends return static and live NodeLists? No thanks. I'm not sure what you would prefer. Make findAll return an Array? (We miss out on a *lot* of cool and useful stuff we could do.) Make findAll return immutable live NodeLists? (Ditto, but for different reasons.) Change qSA to return a NodeArray or Array? (Would be nice, but probably not doable for compat reasons.) Actually, if we add .item to NodeArray then it's entirely possible that we can make qSA return a NodeArray. I'm not entirely convinced that's worth it though. / Jonas
Re: What type should .findAll return
On 11/12/11 10:22 AM, Allen Wirfs-Brock wrote: Note that the only specialness of Array instances relates to what happens when you add new array elements or dynamically change the value of the length property. 1) In ES5 this is just not true; there are various parts of the spec that check [[Class]]. Yes, I know we're working on getting rid of them, but we haven't gotten to that future world yet. 2) In implementations the above may or may not be true. So, if you want the objects to be an immutable, array-like object that inherits from array.prototype through an intermediate prototype there really is no problem. A JS programmer could express this today in ES5: var DOMFindResultProto = Object.create(Array.prototype); //make it inherit from Object.prototype DOMFondResultProto.someMethod = function O() { ...}; //other prototype methods //... function FindResultFactory(nodes) { var obj = Object.create(DOMFindResultProto); for (var i=0; inodes.length;++i) obj[i]=nodes[i]; return Object.freeze(obj); } The result will not have the same performance characteristics as an actual array in many of today's JITs, for what it's worth. You can consider this a bug in those JITs, of course. -Boris
Re: What type should .findAll return
On Nov 12, 2011, at 1:29 AM, Boris Zbarsky wrote: On 11/12/11 10:22 AM, Allen Wirfs-Brock wrote: Note that the only specialness of Array instances relates to what happens when you add new array elements or dynamically change the value of the length property. 1) In ES5 this is just not true; there are various parts of the spec that check [[Class]]. Yes, I know we're working on getting rid of them, but we haven't gotten to that future world yet. Class related distinctions are covered in the document I reference: https://docs.google.com/document/d/1sSUtri6joyOOh23nVDfMbs1wDS7iDMDUFVVeHeRdSIw/edit?authkey=CI-FopgC and are generally secondary issues related to various library routines. For example, whether JSON outputs the properties of an object using [ ] or { }. Notation. The only language level semantic specialness of Array is related to the length invarian 2) In implementations the above may or may not be true. If it isn't the implementation are out of conformance with the standard that applies to them. That means they are buggy and should be fixed. So, if you want the objects to be an immutable, array-like object that inherits from array.prototype through an intermediate prototype there really is no problem. A JS programmer could express this today in ES5: var DOMFindResultProto = Object.create(Array.prototype); //make it inherit from Object.prototype DOMFondResultProto.someMethod = function O() { ...}; //other prototype methods //... function FindResultFactory(nodes) { var obj = Object.create(DOMFindResultProto); for (var i=0; inodes.length;++i) obj[i]=nodes[i]; return Object.freeze(obj); } The result will not have the same performance characteristics as an actual array in many of today's JITs, for what it's worth. You can consider this a bug in those JITs, of course. It's an expected variance on optimization strategies that I don't think is particularly relevent to this discussion. BTW, an equally valid statement would be: the result will have the same performance characteristics as an actual array in many of todays JITs that optimize all integer-indexed properties, regardless of whether or not an object is an actual Array instance. Allen
Re: What type should .findAll return
On 11/13/11 6:10 AM, Allen Wirfs-Brock wrote: Class related distinctions are covered in the document I reference: https://docs.google.com/document/d/1sSUtri6joyOOh23nVDfMbs1wDS7iDMDUFVVeHeRdSIw/edit?authkey=CI-FopgC and are generally secondary issues related to various library routines. Yes, I'm well aware. For example, whether JSON outputs the properties of an object using [ ] or { }. Notation. The only language level semantic specialness of Array is related to the length invarian I think you're drawing a distinction between language level semantics and library routine behavior which is for practical purposes irrelevant to everyone outside the ES5 committee... In practice, at the moment, if you want something that needs to act like an array as far as a web developer is concerned, it's [[Class]] better be Array. In the future, as you note, that might change. If it isn't the implementation are out of conformance with the standard that applies to them. That means they are buggy and should be fixed. The standard does not specify many aspects of implementation behavior, including but not limited to performance characteristics. However, to language _consumers_ (e.g. web developers) those not-specified-in-the-standard aspects are still part of what it means to be an array. It seems to me that there is a serious disconnect here between the way people are thinking about the standard for arrays and the simple it needs to act just like an array in all observable ways request from web developers. For purposes of the ES spec, all that matters is the precise specification of arrays. For purposes of web developers and web specs trying to return array-like objects, these things the standard doesn't care about matter. It's an expected variance on optimization strategies that I don't think is particularly relevent to this discussion. See above. It's 100% relevant to the public-webapps aspects of this discussion. BTW, an equally valid statement would be: the result will have the same performance characteristics as an actual array in many of todays JITs that optimize all integer-indexed properties, regardless of whether or not an object is an actual Array instance. Sure. So? -Boris
Re: What type should .findAll return
On Nov 12, 2011, at 10:27 AM, Boris Zbarsky wrote: On 11/13/11 6:10 AM, Allen Wirfs-Brock wrote: I think you're drawing a distinction between language level semantics and library routine behavior which is for practical purposes irrelevant to everyone outside the ES5 committee... It's relevant to this discussion because you have to decide what web developers actually mean when they say Array. The starting point was that you want NodeArray to be something more than just an Array. So you have do look at all aspects of Array behavior and decide which you care about. The language semantic vs library behavior is relevant because it is often much easer for engine implementers to change or extend library behavior then it is to extend language semantics. In practice, at the moment, if you want something that needs to act like an array as far as a web developer is concerned, it's [[Class]] better be Array. In the future, as you note, that might change. The most important point is that [[Class]] is neither the only nor the most important distinguishing characteristic of ECMAScript built-in Arrays. If you are just arguing about [[Class]] you are missing the point. If it isn't the implementation are out of conformance with the standard that applies to them. That means they are buggy and should be fixed. The standard does not specify many aspects of implementation behavior, including but not limited to performance characteristics. Such as?? While there are still non-performance aspects of implementation that are not yet fully specified we are working hard to eliminate (or at least minimize them). WRT Array, other than performance (including space efficiency) and some aspects of the sort function, what do you think isn't fully specified in ES5.1? I want to know so I can fix that in ES6 However, to language _consumers_ (e.g. web developers) those not-specified-in-the-standard aspects are still part of what it means to be an array. What are they? Really TC39 doesn't want to have such aspects. It seems to me that there is a serious disconnect here between the way people are thinking about the standard for arrays and the simple it needs to act just like an array in all observable ways request from web developers. all observable ways means no methods that aren't already on Array.prototype. I might think if would be fine for .findAll to just return an actual Array instance. But others seem to want to augment that behavior so all observable ways does not seem to apply. For purposes of the ES spec, all that matters is the precise specification of arrays. For purposes of web developers and web specs trying to return array-like objects, these things the standard doesn't care about matter. I have to say that I think you are totally mischaracterizing the ES spec and the position of TC39. I don't understand why? It's an expected variance on optimization strategies that I don't think is particularly relevent to this discussion. See above. It's 100% relevant to the public-webapps aspects of this discussion. Still not clear, are you saying that all implementation are expect to apply the same optimizations? That clearly isn't the case today. BTW, an equally valid statement would be: the result will have the same performance characteristics as an actual array in many of todays JITs that optimize all integer-indexed properties, regardless of whether or not an object is an actual Array instance. Sure. So? You bought of this implementation specific performance point, for some reason. I'm just pointing out that your argument goes both ways. Personally, it sounds to me like design by premature optimization. Allen
Re: What type should .findAll return
Yehuda Katz (ph) 718.877.1325 On Sat, Nov 12, 2011 at 11:51 AM, Allen Wirfs-Brock al...@wirfs-brock.comwrote: On Nov 12, 2011, at 10:27 AM, Boris Zbarsky wrote: On 11/13/11 6:10 AM, Allen Wirfs-Brock wrote: I think you're drawing a distinction between language level semantics and library routine behavior which is for practical purposes irrelevant to everyone outside the ES5 committee... It's relevant to this discussion because you have to decide what web developers actually mean when they say Array. The starting point was that you want NodeArray to be something more than just an Array. So you have do look at all aspects of Array behavior and decide which you care about. The language semantic vs library behavior is relevant because it is often much easer for engine implementers to change or extend library behavior then it is to extend language semantics. In practice, at the moment, if you want something that needs to act like an array as far as a web developer is concerned, it's [[Class]] better be Array. In the future, as you note, that might change. The most important point is that [[Class]] is neither the only nor the most important distinguishing characteristic of ECMAScript built-in Arrays. If you are just arguing about [[Class]] you are missing the point. I think it's worth noting that [[Class]] is actually used by jQuery and other implementations to identify whether an object is a real Array. It may be the case that we could revisit some of those cases, but the technique of using [[Class]] to get a less buggy picture of what an object is (compared to typeof etc.) is pretty common. We use it in SproutCore as well. The jQuery.type function: https://github.com/jquery/jquery/blob/master/src/core.js#L491-495 The class2type map: https://github.com/jquery/jquery/blob/master/src/core.js#L877-879 toString in that function is declared above as Object.prototype.toString. That said, of course other aspects of the observed behavior, such as its exposed methods, matter as well. If it isn't the implementation are out of conformance with the standard that applies to them. That means they are buggy and should be fixed. The standard does not specify many aspects of implementation behavior, including but not limited to performance characteristics. Such as?? While there are still non-performance aspects of implementation that are not yet fully specified we are working hard to eliminate (or at least minimize them). WRT Array, other than performance (including space efficiency) and some aspects of the sort function, what do you think isn't fully specified in ES5.1? I want to know so I can fix that in ES6 However, to language _consumers_ (e.g. web developers) those not-specified-in-the-standard aspects are still part of what it means to be an array. What are they? Really TC39 doesn't want to have such aspects. It seems to me that there is a serious disconnect here between the way people are thinking about the standard for arrays and the simple it needs to act just like an array in all observable ways request from web developers. all observable ways means no methods that aren't already on Array.prototype. I might think if would be fine for .findAll to just return an actual Array instance. But others seem to want to augment that behavior so all observable ways does not seem to apply. For purposes of the ES spec, all that matters is the precise specification of arrays. For purposes of web developers and web specs trying to return array-like objects, these things the standard doesn't care about matter. I have to say that I think you are totally mischaracterizing the ES spec and the position of TC39. I don't understand why? It's an expected variance on optimization strategies that I don't think is particularly relevent to this discussion. See above. It's 100% relevant to the public-webapps aspects of this discussion. Still not clear, are you saying that all implementation are expect to apply the same optimizations? That clearly isn't the case today. BTW, an equally valid statement would be: the result will have the same performance characteristics as an actual array in many of todays JITs that optimize all integer-indexed properties, regardless of whether or not an object is an actual Array instance. Sure. So? You bought of this implementation specific performance point, for some reason. I'm just pointing out that your argument goes both ways. Personally, it sounds to me like design by premature optimization. Allen
Re: What type should .findAll return
On 11/13/11 8:51 AM, Allen Wirfs-Brock wrote: It's relevant to this discussion because you have to decide what web developers actually mean when they say Array. Yes, agreed. The most important point is that [[Class]] is neither the only nor the most important distinguishing characteristic of ECMAScript built-in Arrays. Agreed on the former; I don't think it matters that much how important it is. It's just a distinguishing characteristic, period. The standard does not specify many aspects of implementation behavior, including but not limited to performance characteristics. Such as?? While there are still non-performance aspects of implementation that are not yet fully specified we are working hard to eliminate (or at least minimize them). WRT Array, other than performance (including space efficiency) and some aspects of the sort function, what do you think isn't fully specified in ES5.1? For arrays specifically, I believe performance and space are the only issues off the top of my head, other than the sort thing you mention. It seems to me that there is a serious disconnect here between the way people are thinking about the standard for arrays and the simple it needs to act just like an array in all observable ways request from web developers. all observable ways means no methods that aren't already on Array.prototype. I might think if would be fine for .findAll to just return an actual Array instance. But others seem to want to augment that behavior so all observable ways does not seem to apply. Yeah, different people have different definitions of all observable ways too... ;) For purposes of the ES spec, all that matters is the precise specification of arrays. For purposes of web developers and web specs trying to return array-like objects, these things the standard doesn't care about matter. I have to say that I think you are totally mischaracterizing the ES spec and the position of TC39. Unless the ES spec starts mandating something about array performance, I don't think I am. Note that I don't think this is a problem for ES per se. I do think that for the nodelists we're considering here mandating that they should perform like arrays do would not be an unreasonable requirement on the DOM side. See above. It's 100% relevant to the public-webapps aspects of this discussion. Still not clear, are you saying that all implementation are expect to apply the same optimizations? I think expecting implementations to apply the same optimizations to these lists as to things created with |new Array| would not be unreasonable. These optimizations may differ in different implementations, of course. -Boris
What type should .findAll return
Hi All, So, we've debated a lot the exact syntax for .find/.findAll. However I intentionally requested that we split out the discussions about return type for .findAll to a separate thread. So I'm starting that thread here. There are a few goals for the return'ed object that I've envisioned based on discussions so far: 1. It should have at least all of the non-mutating Array methods on it. Possibly the mutating methods too if we allow the returned object to be mutable. 2. It should have a object on the prototype chain where we can insert functions that are specifically useful for lists of nodes. Examples include .find/.findAll/.matchesSelector/.remove/.addEventListener 3. It would be good if it had the Array prototype object on it's prototype chain so that if Array.prototype was extended, it would affect this object too. 4. The object will *not* be live since live results from selector matching is slow. Since the returned object won't be live, I don't see a reason to make it immutable. Hence it seems like we could put Array.prototype on the prototype chain which would immediately make all non-mutating as well as mutating functions available on the object. We should also insert a new prototype object in the prototype chain. Hence we end up with something like: object - [some type].prototype - Array.prototype - Object.prototype. And to ensure that the object acts as much as possible as an array it should also have it's [[Class]] set to that of an array. This has subtle effects on a number of functions. For example it affects what Object.toString() and Array.isArray returns, it affects how Array.concat behaves, and it affects the JSON serializer. I'm not sure if setting the [[Class]] to that of an array also gives the object the magical .length property, but if it doesn't, we need to also define that the returned object has such a property. Note that for Arrays, .length doesn't live on the prototype chain, but is rather a special property on the object itself. In other words, the returned object is exactly what you'd get if you did: a = new Array; a.__proto__ = [some type].prototype; [some type].prototype.__proto__ = Array.prototype; and then filled a with the set of nodes which matched the selector passed to .findAll. So the remaining question is, what should we use for [some type]. One option is to use NodeList. However this would result in NodeLists having Array.prototype on it's prototype chain. Including all mutating functions. This is iffy in general since NodeLists are returned from several APIs which return objects which represent a live result of a query. For example .getElementsByTagName, .getElementsByClassName and .childNodes. An additional source of iffiness with this idea is that several of the mutating methods on Array.prototype don't throw if called on a immutable objects. For example .pop, .shift, .sort and .reverse all would not throw if called on an empty immutable list. Hence I propose that we add a new type. I don't care much for naming things so I'll just suggest NodeArray for now and let others fight it out over the name. For now we can leave NodeArray as empty and just let it be an extension point for page authors. We can discuss separately if .findAll/.matchesSelector should be added to NodeArray, and if so how they should behave. However, we should probably use NodeArray to fix one of the problems with some of the functions on Array.prototype. For example Array.prototype.filter always returns a new Array object. This would mean that: elem.findAll(...).filter(function(node) { ... }); will return a plain Array and not a NodeArray. However we could make NodeArray override all such functions and keep their behavior identical except that they return NodeArrays. Another way to fix this problem would be to change the definition of Array.prototype.filter, but I have no idea if that's doable, or how that would be done. What do people think? / Jonas
Re: What type should .findAll return
As a web developer, having DOM methods which return real arrays so we no longer have to call `toArray(nodeList)` or `[].slice.call(nodeList)` would be awesome. On Fri, Nov 11, 2011 at 9:05 AM, Jonas Sicking jo...@sicking.cc wrote: Hi All, So, we've debated a lot the exact syntax for .find/.findAll. However I intentionally requested that we split out the discussions about return type for .findAll to a separate thread. So I'm starting that thread here. There are a few goals for the return'ed object that I've envisioned based on discussions so far: 1. It should have at least all of the non-mutating Array methods on it. Possibly the mutating methods too if we allow the returned object to be mutable. 2. It should have a object on the prototype chain where we can insert functions that are specifically useful for lists of nodes. Examples include .find/.findAll/.matchesSelector/.remove/.addEventListener 3. It would be good if it had the Array prototype object on it's prototype chain so that if Array.prototype was extended, it would affect this object too. 4. The object will *not* be live since live results from selector matching is slow. Since the returned object won't be live, I don't see a reason to make it immutable. Hence it seems like we could put Array.prototype on the prototype chain which would immediately make all non-mutating as well as mutating functions available on the object. We should also insert a new prototype object in the prototype chain. Hence we end up with something like: object - [some type].prototype - Array.prototype - Object.prototype. And to ensure that the object acts as much as possible as an array it should also have it's [[Class]] set to that of an array. This has subtle effects on a number of functions. For example it affects what Object.toString() and Array.isArray returns, it affects how Array.concat behaves, and it affects the JSON serializer. I'm not sure if setting the [[Class]] to that of an array also gives the object the magical .length property, but if it doesn't, we need to also define that the returned object has such a property. Note that for Arrays, .length doesn't live on the prototype chain, but is rather a special property on the object itself. In other words, the returned object is exactly what you'd get if you did: a = new Array; a.__proto__ = [some type].prototype; [some type].prototype.__proto__ = Array.prototype; and then filled a with the set of nodes which matched the selector passed to .findAll. So the remaining question is, what should we use for [some type]. One option is to use NodeList. However this would result in NodeLists having Array.prototype on it's prototype chain. Including all mutating functions. This is iffy in general since NodeLists are returned from several APIs which return objects which represent a live result of a query. For example .getElementsByTagName, .getElementsByClassName and .childNodes. Not to mention, that there must be a ton of code out there that assumes a nodeList is not an array (mediocre feature detection code). An additional source of iffiness with this idea is that several of the mutating methods on Array.prototype don't throw if called on a immutable objects. For example .pop, .shift, .sort and .reverse all would not throw if called on an empty immutable list. Hence I propose that we add a new type. I don't care much for naming things so I'll just suggest NodeArray for now and let others fight it out over the name. For now we can leave NodeArray as empty and just let it be an extension point for page authors. We can discuss separately if .findAll/.matchesSelector should be added to NodeArray, and if so how they should behave. However, we should probably use NodeArray to fix one of the problems with some of the functions on Array.prototype. For example Array.prototype.filter always returns a new Array object. This would mean that: elem.findAll(...).filter(function(node) { ... }); will return a plain Array and not a NodeArray. However we could make NodeArray override all such functions and keep their behavior identical except that they return NodeArrays. Another way to fix this problem would be to change the definition of Array.prototype.filter, but I have no idea if that's doable, or how that would be done. That would involve hackling with es-discuss. I send an email to their mailing list https://mail.mozilla.org/pipermail/es-discuss/2011-November/018242.html What do people think? overall it's a great idea. It is however a shame we duplicate functionality with querySelectorAll / Jonas
Re: What type should .findAll return
On Fri, Nov 11, 2011 at 1:05 AM, Jonas Sicking jo...@sicking.cc wrote: And to ensure that the object acts as much as possible as an array it should also have it's [[Class]] set to that of an array. This has subtle effects on a number of functions. For example it affects what Object.toString() and Array.isArray returns, it affects how Array.concat behaves, and it affects the JSON serializer. Could you point me to an explanation of what [[Class]] represents in ecmascript? It's a little hard to search for. Another way to fix this problem would be to change the definition of Array.prototype.filter, but I have no idea if that's doable, or how that would be done. I prefer this if possible. What do people think? +1 ~TJ
Re: What type should .findAll return
* Tab Atkins Jr. wrote: Could you point me to an explanation of what [[Class]] represents in ecmascript? It's a little hard to search for. http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf Section 8.6.2. for instance. -- Björn Höhrmann · mailto:bjo...@hoehrmann.de · http://bjoern.hoehrmann.de Am Badedeich 7 · Telefon: +49(0)160/4415681 · http://www.bjoernsworld.de 25899 Dagebüll · PGP Pub. KeyID: 0xA4357E78 · http://www.websitedev.de/
Re: What type should .findAll return
On Fri, Nov 11, 2011 at 3:46 PM, Tab Atkins Jr. jackalm...@gmail.comwrote: On Fri, Nov 11, 2011 at 1:05 AM, Jonas Sicking jo...@sicking.cc wrote: And to ensure that the object acts as much as possible as an array it should also have it's [[Class]] set to that of an array. This has subtle effects on a number of functions. For example it affects what Object.toString() and Array.isArray returns, it affects how Array.concat behaves, and it affects the JSON serializer. Could you point me to an explanation of what [[Class]] represents in ecmascript? It's a little hard to search for. [[Class]] is simply an internal property http://es5.github.com/#x8.6.2containing a string like Array, String, Object, etc. It's mainly used throughout the ES specification to determine how internal methods should behave to inputs. For example JSON.parse http://es5.github.com/#x15.12.2 checks for the [[Class]] of Array and adjusts the output accordingly. A quick string search on Array will find you all occurrences of the internals relying on [[Class]] being set to Array Another way to fix this problem would be to change the definition of Array.prototype.filter, but I have no idea if that's doable, or how that would be done. I prefer this if possible. What do people think? +1 ~TJ
Re: What type should .findAll return
On Nov 11, 2011, at 1:05 AM, Jonas Sicking wrote: Hi All, So, we've debated a lot the exact syntax for .find/.findAll. However I intentionally requested that we split out the discussions about return type for .findAll to a separate thread. So I'm starting that thread here. There are a few goals for the return'ed object that I've envisioned based on discussions so far: 1. It should have at least all of the non-mutating Array methods on it. Possibly the mutating methods too if we allow the returned object to be mutable. 2. It should have a object on the prototype chain where we can insert functions that are specifically useful for lists of nodes. Examples include .find/.findAll/.matchesSelector/.remove/.addEventListener 3. It would be good if it had the Array prototype object on it's prototype chain so that if Array.prototype was extended, it would affect this object too. 4. The object will *not* be live since live results from selector matching is slow. Since the returned object won't be live, I don't see a reason to make it immutable. Hence it seems like we could put Array.prototype on the prototype chain which would immediately make all non-mutating as well as mutating functions available on the object. We should also insert a new prototype object in the prototype chain. Hence we end up with something like: object - [some type].prototype - Array.prototype - Object.prototype. And to ensure that the object acts as much as possible as an array it should also have it's [[Class]] set to that of an array. This is not something to do lightly -- at least cross-post the first message to es-disc...@mozilla.org and set reply-to followups-to. Cc'ing Allen. Note that [[Class]] is going away in ES.next. The internal methods and properties of ECMA-262 are not arbitrary extension points for other specs to use without consultation. /be This has subtle effects on a number of functions. For example it affects what Object.toString() and Array.isArray returns, it affects how Array.concat behaves, and it affects the JSON serializer. I'm not sure if setting the [[Class]] to that of an array also gives the object the magical .length property, but if it doesn't, we need to also define that the returned object has such a property. Note that for Arrays, .length doesn't live on the prototype chain, but is rather a special property on the object itself. In other words, the returned object is exactly what you'd get if you did: a = new Array; a.__proto__ = [some type].prototype; [some type].prototype.__proto__ = Array.prototype; and then filled a with the set of nodes which matched the selector passed to .findAll. So the remaining question is, what should we use for [some type]. One option is to use NodeList. However this would result in NodeLists having Array.prototype on it's prototype chain. Including all mutating functions. This is iffy in general since NodeLists are returned from several APIs which return objects which represent a live result of a query. For example .getElementsByTagName, .getElementsByClassName and .childNodes. An additional source of iffiness with this idea is that several of the mutating methods on Array.prototype don't throw if called on a immutable objects. For example .pop, .shift, .sort and .reverse all would not throw if called on an empty immutable list. Hence I propose that we add a new type. I don't care much for naming things so I'll just suggest NodeArray for now and let others fight it out over the name. For now we can leave NodeArray as empty and just let it be an extension point for page authors. We can discuss separately if .findAll/.matchesSelector should be added to NodeArray, and if so how they should behave. However, we should probably use NodeArray to fix one of the problems with some of the functions on Array.prototype. For example Array.prototype.filter always returns a new Array object. This would mean that: elem.findAll(...).filter(function(node) { ... }); will return a plain Array and not a NodeArray. However we could make NodeArray override all such functions and keep their behavior identical except that they return NodeArrays. Another way to fix this problem would be to change the definition of Array.prototype.filter, but I have no idea if that's doable, or how that would be done. What do people think? / Jonas
Re: What type should .findAll return
On Fri, Nov 11, 2011 at 10:06 AM, Brendan Eich bren...@mozilla.org wrote: On Nov 11, 2011, at 1:05 AM, Jonas Sicking wrote: Hi All, So, we've debated a lot the exact syntax for .find/.findAll. However I intentionally requested that we split out the discussions about return type for .findAll to a separate thread. So I'm starting that thread here. There are a few goals for the return'ed object that I've envisioned based on discussions so far: 1. It should have at least all of the non-mutating Array methods on it. Possibly the mutating methods too if we allow the returned object to be mutable. 2. It should have a object on the prototype chain where we can insert functions that are specifically useful for lists of nodes. Examples include .find/.findAll/.matchesSelector/.remove/.addEventListener 3. It would be good if it had the Array prototype object on it's prototype chain so that if Array.prototype was extended, it would affect this object too. 4. The object will *not* be live since live results from selector matching is slow. Since the returned object won't be live, I don't see a reason to make it immutable. Hence it seems like we could put Array.prototype on the prototype chain which would immediately make all non-mutating as well as mutating functions available on the object. We should also insert a new prototype object in the prototype chain. Hence we end up with something like: object - [some type].prototype - Array.prototype - Object.prototype. And to ensure that the object acts as much as possible as an array it should also have it's [[Class]] set to that of an array. This is not something to do lightly -- at least cross-post the first message to es-disc...@mozilla.org and set reply-to followups-to. Cc'ing Allen. Note that [[Class]] is going away in ES.next. The internal methods and properties of ECMA-262 are not arbitrary extension points for other specs to use without consultation. Yup, that's why i cc'ed public-script-coord. Note that what I'm suggesting in this thread is to create a real normal Array. Just one with an extra object inserted in it's prototype chain. So if [[Class]] is going away in ES.next that shouldn't be a problem. Whatever will happen to Arrays when that happens, should happen to NodeArrays. The separate issue of making .filter and friends work can be solved in multiple ways. At least some of which require no changes to Array.filter if that is preferable from a language point of view. Granted, it would be nice if Array.filter(elem.findAll(...), function(element) { ... }) worked too, and that *would* require changes to ES. / Jonas
Re: What type should .findAll return
On 11/11/11 10:05 PM, Jonas Sicking wrote: In other words, the returned object is exactly what you'd get if you did: a = new Array; a.__proto__ = [some type].prototype; [some type].prototype.__proto__ = Array.prototype; For what it's worth, at least some JITs deoptimize |a| if you do that. We'd probably need to do something to make sure that _doesn't_ happen in this case, right? -Boris
Re: What type should .findAll return
On Nov 11, 2011, at 10:44 AM, Jonas Sicking wrote: On Fri, Nov 11, 2011 at 10:06 AM, Brendan Eich bren...@mozilla.org wrote: On Nov 11, 2011, at 1:05 AM, Jonas Sicking wrote: And to ensure that the object acts as much as possible as an array it should also have it's [[Class]] set to that of an array. This is not something to do lightly -- at least cross-post the first message to es-disc...@mozilla.org and set reply-to followups-to. Cc'ing Allen. Note that [[Class]] is going away in ES.next. The internal methods and properties of ECMA-262 are not arbitrary extension points for other specs to use without consultation. Yup, that's why i cc'ed public-script-coord. That's why I'm asking you to cc: es-discuss. I expect Allen will catch up with this thread, but you may get more prompt responses from various people by using es-discuss for the initial message. Note that what I'm suggesting in this thread is to create a real normal Array. Just one with an extra object inserted in it's prototype chain. That's not a real normal Array then. Boris mentioned one issue (optimization). Let's call it an extended array. ES.next should support user-extended arrays via the | operator, so this isn't something bad, but it's not exactly an array. So if [[Class]] is going away in ES.next that shouldn't be a problem. Whatever will happen to Arrays when that happens, should happen to NodeArrays. Allen analyzed how [[Class]] is used in ES1-5, and broke down the cases. Some of these change to a different or more generic way of discriminating on class. Others still need an internal property. Notable among the latter is the string name disclosed by Object.prototype.toString.call(anArray). The deeper issue for arrays is the custom [[DefineOwnProperty]] (ES5) or [[Put]] (ES1-3) that maintains length to be one greater than greatest index provided the index is 2^31 - 1. The separate issue of making .filter and friends work can be solved in multiple ways. At least some of which require no changes to Array.filter if that is preferable from a language point of view. This sounds right. /be
Re: What type should .findAll return
On Nov 11, 2011, at 7:46 AM, Tab Atkins Jr. wrote: On Fri, Nov 11, 2011 at 1:05 AM, Jonas Sicking jo...@sicking.cc wrote: And to ensure that the object acts as much as possible as an array it should also have it's [[Class]] set to that of an array. This has subtle effects on a number of functions. For example it affects what Object.toString() and Array.isArray returns, it affects how Array.concat behaves, and it affects the JSON serializer. Could you point me to an explanation of what [[Class]] represents in ecmascript? It's a little hard to search for. this turns out to not be such a simple question see https://docs.google.com/document/d/1sSUtri6joyOOh23nVDfMbs1wDS7iDMDUFVVeHeRdSIw/edit?authkey=CI-FopgC [[Class]] has been (mis-??)used for many things. This is why we want to cleanup up for the future. Allen
Re: What type should .findAll return
Note that the only specialness of Array instances relates to what happens when you add new array elements or dynamically change the value of the length property. If the array instance is immutable you can't do any of those things so its specialness essentially disappears. So, if you want the objects to be an immutable, array-like object that inherits from array.prototype through an intermediate prototype there really is no problem. A JS programmer could express this today in ES5: var DOMFindResultProto = Object.create(Array.prototype); //make it inherit from Object.prototype DOMFondResultProto.someMethod = function O() { ...}; //other prototype methods //... function FindResultFactory(nodes) { var obj = Object.create(DOMFindResultProto); for (var i=0; inodes.length;++i) obj[i]=nodes[i]; return Object.freeze(obj); } However, if you want the object to be mutable and to act like a real array, then it has to have the array specialness. The specialness comes, not from the [[Class]] property but from its alternative definitions of [[DefineOwnProperty]] (see ES5.1 spec. 15.4.5.1). In ES.next a JS programmer will be able to easily define such an object. But for ES5 it takes special implementation level intervention.Since this capability is going to ultimately be in ES.next I don't see why you couldn't do it now, assuming the the engine implementors are all willing to cooperate. Basically, you would specify that the [[Prototype]] of the instances inherits from Array.prototype and that the instances use the [[DefineOwnProperty]] specification from ES5 section 15.4.5.1. In either case, you would be specifying a new kind of ES native object rather than a host object'. BTW, I think that either the immutable or mutable approach would work. However, since the collection is not live I don't see why you would really care whether or not a client mutated it. If they want to process it by deleting elements after they are examined, so what? Allen On Nov 11, 2011, at 12:20 PM, Boris Zbarsky wrote: On 11/11/11 10:05 PM, Jonas Sicking wrote: In other words, the returned object is exactly what you'd get if you did: a = new Array; a.__proto__ = [some type].prototype; [some type].prototype.__proto__ = Array.prototype; For what it's worth, at least some JITs deoptimize |a| if you do that. We'd probably need to do something to make sure that _doesn't_ happen in this case, right? -Boris
Re: What type should .findAll return
On Fri, Nov 11, 2011 at 1:22 PM, Allen Wirfs-Brock al...@wirfs-brock.com wrote: However, if you want the object to be mutable and to act like a real array, then it has to have the array specialness. The specialness comes, not from the [[Class]] property but from its alternative definitions of [[DefineOwnProperty]] (see ES5.1 spec. 15.4.5.1). The Array-like thing discussed in this thread is going to be mutable. In ES.next a JS programmer will be able to easily define such an object. But for ES5 it takes special implementation level intervention. Since this capability is going to ultimately be in ES.next I don't see why you couldn't do it now, assuming the the engine implementors are all willing to cooperate. Basically, you would specify that the [[Prototype]] of the instances inherits from Array.prototype and that the instances use the [[DefineOwnProperty]] specification from ES5 section 15.4.5.1. In either case, you would be specifying a new kind of ES native object rather than a host object'. BTW, I think that either the immutable or mutable approach would work. However, since the collection is not live I don't see why you would really care whether or not a client mutated it. If they want to process it by deleting elements after they are examined, so what? Exactly, this is why I'm proposing that it should be mutable. This does still leave the problem of making Array.filter(myNodeArray, function(el) { ... }) work though. I.e. I think we'd like it to return a NodeArray rather than a plain Array. More importantly, we want myNodeArray.filter(function(el){ ... }) to return a NodeArray. This would be doable by putting a special version of filter on NodeArray.prototype which would shadow Array.prototype.filter. This would make myNodeArray.filter work, but not Array.filter. I'm happy to start a separate thread on es-discuss about this, but I'm worried that it'll fragment the current thread. / Jonas
Re: What type should .findAll return
On Nov 11, 2011, at 2:16 PM, Jonas Sicking wrote: On Fri, Nov 11, 2011 at 1:22 PM, Allen Wirfs-Brock al...@wirfs-brock.com wrote: BTW, I think that either the immutable or mutable approach would work. However, since the collection is not live I don't see why you would really care whether or not a client mutated it. If they want to process it by deleting elements after they are examined, so what? Exactly, this is why I'm proposing that it should be mutable. This does still leave the problem of making Array.filter(myNodeArray, function(el) { ... }) work though. I.e. I think we'd like it to return a NodeArray rather than a plain Array. This is a problem for ES=5. Filter and all the other similar Array.prototype functions are specified to produce an object created as if by calling: new Array(); I have a scheme that we can probably get in place for ES.next that would allow filter and friends to produce NodeArray's for you, but I don't see how that helps right now. More importantly, we want myNodeArray.filter(function(el){ ... }) to return a NodeArray. This would be doable by putting a special version of filter on NodeArray.prototype which would shadow Array.prototype.filter. It isn't just filter that creates new instances that you would probably want to be NodeArrays. Also at least(I might have missed other when I just checkeds): concat, slice, splice, map Over-riding them explicitly for NodeArray would be an immediate fix, but wouldn't solve the problem for future additions to Array.prototype. However, if you assume that ES.next is going to provide the needed extension mechanism then you should also assume that it will use it for any new Array.prototype methods and they should pretty much just work. This would make myNodeArray.filter work, but not Array.filter. An inherent problem with this approach. But if your NodeArrays supplies correctly working over-rides there is probably little reason somebody would try to use the Array.prototype versions with NodeArrays. I don't see a way around this short of modifying the specification of the Array.prototype methods. That seems like a job for ES.next rather than a DOM spec. I'm happy to start a separate thread on es-discuss about this, but I'm worried that it'll fragment the current thread. In theory, public-script-coord exists for exactly this sort of discussion and the ESdiscuss people who care should be subscripted. Rather than starting a new thread, perhaps should should just post to es-discuss a pointer to this thread. Allen
Re: What type should .findAll return
On Nov 11, 2011, at 3:07 PM, Allen Wirfs-Brock wrote: I'm happy to start a separate thread on es-discuss about this, but I'm worried that it'll fragment the current thread. In theory, public-script-coord exists for exactly this sort of discussion and the ESdiscuss people who care should be subscripted. Rather than starting a new thread, perhaps should should just post to es-discuss a pointer to this thread. Turns out (thanks Jake!) we do have an es-discuss thread of interest: https://mail.mozilla.org/pipermail/es-discuss/2011-November/018242.html /be
Re: What type should .findAll return
On Fri, Nov 11, 2011 at 3:07 PM, Allen Wirfs-Brock al...@wirfs-brock.com wrote: On Nov 11, 2011, at 2:16 PM, Jonas Sicking wrote: On Fri, Nov 11, 2011 at 1:22 PM, Allen Wirfs-Brock al...@wirfs-brock.com wrote: BTW, I think that either the immutable or mutable approach would work. However, since the collection is not live I don't see why you would really care whether or not a client mutated it. If they want to process it by deleting elements after they are examined, so what? Exactly, this is why I'm proposing that it should be mutable. This does still leave the problem of making Array.filter(myNodeArray, function(el) { ... }) work though. I.e. I think we'd like it to return a NodeArray rather than a plain Array. This is a problem for ES=5. Filter and all the other similar Array.prototype functions are specified to produce an object created as if by calling: new Array(); I have a scheme that we can probably get in place for ES.next that would allow filter and friends to produce NodeArray's for you, but I don't see how that helps right now. Well, if we can get implementations to implement this new scheme for the existing filter-like functions at the same time as they implement .findAll, then we should be golden. More importantly, we want myNodeArray.filter(function(el){ ... }) to return a NodeArray. This would be doable by putting a special version of filter on NodeArray.prototype which would shadow Array.prototype.filter. It isn't just filter that creates new instances that you would probably want to be NodeArrays. Also at least(I might have missed other when I just checkeds): concat, slice, splice, map Indeed, I was just using filter as an example. Over-riding them explicitly for NodeArray would be an immediate fix, but wouldn't solve the problem for future additions to Array.prototype. However, if you assume that ES.next is going to provide the needed extension mechanism then you should also assume that it will use it for any new Array.prototype methods and they should pretty much just work. Indeed. If we went down this path we would have to continuously update the spec to make NodeArray override any filter-like methods that are added to Array. This would make myNodeArray.filter work, but not Array.filter. An inherent problem with this approach. But if your NodeArrays supplies correctly working over-rides there is probably little reason somebody would try to use the Array.prototype versions with NodeArrays. Note that I was saying Array.filter and not Array.prototype.filter. My assumption was that if people call Array.prototype with an Array as the first argument, they would also do so with a NodeArray as first argument. I don't see a way around this short of modifying the specification of the Array.prototype methods. That seems like a job for ES.next rather than a DOM spec. Definitely, hence the cc :) I'm happy to start a separate thread on es-discuss about this, but I'm worried that it'll fragment the current thread. In theory, public-script-coord exists for exactly this sort of discussion and the ESdiscuss people who care should be subscripted. Rather than starting a new thread, perhaps should should just post to es-discuss a pointer to this thread. Will do! / Jonas
Re: What type should .findAll return
On Nov 11, 2011, at 3:57 PM, Jonas Sicking wrote: On Fri, Nov 11, 2011 at 3:07 PM, Allen Wirfs-Brock al...@wirfs-brock.com wrote: ... This is a problem for ES=5. Filter and all the other similar Array.prototype functions are specified to produce an object created as if by calling: new Array(); I have a scheme that we can probably get in place for ES.next that would allow filter and friends to produce NodeArray's for you, but I don't see how that helps right now. Well, if we can get implementations to implement this new scheme for the existing filter-like functions at the same time as they implement .findAll, then we should be golden. the scheme depends upon other Es.next features including private names. It isn't clear that if you start pulling that thread how far it extends. But perhaps, it might fly... ... This would make myNodeArray.filter work, but not Array.filter. An inherent problem with this approach. But if your NodeArrays supplies correctly working over-rides there is probably little reason somebody would try to use the Array.prototype versions with NodeArrays. Note that I was saying Array.filter and not Array.prototype.filter. My assumption was that if people call Array.prototype with an Array as the first argument, they would also do so with a NodeArray as first argument. Array.filter and friends (in contrast to Array.prototype.filter) are not in ES5 and, so far, have not made the ES.next cut. Personally, I'm not a bit fan of them for exactly this reason. If you are building object-oriented class hierarchies you want to use methods, not global function that can't easily be virtually dispatched. Allen
Re: What type should .findAll return
Any DOM NodeList/NodeArray could be converted into a real array by passing to Array.from( array like ) http://wiki.ecmascript.org/doku.php?id=strawman:array_extras Avoids creating yet another DOM NodeThing. /Rick On Nov 11, 2011, at 6:57 PM, Jonas Sicking jo...@sicking.cc wrote: On Fri, Nov 11, 2011 at 3:07 PM, Allen Wirfs-Brock al...@wirfs-brock.com wrote: On Nov 11, 2011, at 2:16 PM, Jonas Sicking wrote: On Fri, Nov 11, 2011 at 1:22 PM, Allen Wirfs-Brock al...@wirfs-brock.com wrote: BTW, I think that either the immutable or mutable approach would work. However, since the collection is not live I don't see why you would really care whether or not a client mutated it. If they want to process it by deleting elements after they are examined, so what? Exactly, this is why I'm proposing that it should be mutable. This does still leave the problem of making Array.filter(myNodeArray, function(el) { ... }) work though. I.e. I think we'd like it to return a NodeArray rather than a plain Array. This is a problem for ES=5. Filter and all the other similar Array.prototype functions are specified to produce an object created as if by calling: new Array(); I have a scheme that we can probably get in place for ES.next that would allow filter and friends to produce NodeArray's for you, but I don't see how that helps right now. Well, if we can get implementations to implement this new scheme for the existing filter-like functions at the same time as they implement .findAll, then we should be golden. More importantly, we want myNodeArray.filter(function(el){ ... }) to return a NodeArray. This would be doable by putting a special version of filter on NodeArray.prototype which would shadow Array.prototype.filter. It isn't just filter that creates new instances that you would probably want to be NodeArrays. Also at least(I might have missed other when I just checkeds): concat, slice, splice, map Indeed, I was just using filter as an example. Over-riding them explicitly for NodeArray would be an immediate fix, but wouldn't solve the problem for future additions to Array.prototype. However, if you assume that ES.next is going to provide the needed extension mechanism then you should also assume that it will use it for any new Array.prototype methods and they should pretty much just work. Indeed. If we went down this path we would have to continuously update the spec to make NodeArray override any filter-like methods that are added to Array. This would make myNodeArray.filter work, but not Array.filter. An inherent problem with this approach. But if your NodeArrays supplies correctly working over-rides there is probably little reason somebody would try to use the Array.prototype versions with NodeArrays. Note that I was saying Array.filter and not Array.prototype.filter. My assumption was that if people call Array.prototype with an Array as the first argument, they would also do so with a NodeArray as first argument. I don't see a way around this short of modifying the specification of the Array.prototype methods. That seems like a job for ES.next rather than a DOM spec. Definitely, hence the cc :) I'm happy to start a separate thread on es-discuss about this, but I'm worried that it'll fragment the current thread. In theory, public-script-coord exists for exactly this sort of discussion and the ESdiscuss people who care should be subscripted. Rather than starting a new thread, perhaps should should just post to es-discuss a pointer to this thread. Will do! / Jonas
Re: What type should .findAll return
On Fri, Nov 11, 2011 at 5:35 PM, Rick Waldron waldron.r...@gmail.com wrote: Any DOM NodeList/NodeArray could be converted into a real array by passing to Array.from( array like ) http://wiki.ecmascript.org/doku.php?id=strawman:array_extras Avoids creating yet another DOM NodeThing. Jonas explains very well why we don't want a real Array, but rather something that just acts like an Array. ~TJ
Re: What type should .findAll return
On Fri, Nov 11, 2011 at 5:52 PM, Rick Waldron waldron.r...@gmail.com wrote: Right, but I'm saying: why create yet more stuff in the DOM? findAll will return a NodeArray while querySelectorAll and friends return static and live NodeLists? No thanks. I'm not sure what you would prefer. Make findAll return an Array? (We miss out on a *lot* of cool and useful stuff we could do.) Make findAll return immutable live NodeLists? (Ditto, but for different reasons.) Change qSA to return a NodeArray or Array? (Would be nice, but probably not doable for compat reasons.) ~TJ
Re: What type should .findAll return
On Fri, Nov 11, 2011 at 5:59 PM, Tab Atkins Jr. jackalm...@gmail.com wrote: On Fri, Nov 11, 2011 at 5:52 PM, Rick Waldron waldron.r...@gmail.com wrote: Right, but I'm saying: why create yet more stuff in the DOM? findAll will return a NodeArray while querySelectorAll and friends return static and live NodeLists? No thanks. I'm not sure what you would prefer. Make findAll return an Array? (We miss out on a *lot* of cool and useful stuff we could do.) Make findAll return immutable live NodeLists? (Ditto, but for different reasons.) Change qSA to return a NodeArray or Array? (Would be nice, but probably not doable for compat reasons.) Actually, if we add .item to NodeArray then it's entirely possible that we can make qSA return a NodeArray. I'm not entirely convinced that's worth it though. / Jonas