Re: array like objects
On 2009-12-15, at 23:28, Brendan Eich wrote: Something more like Self, in other words. I still wonder if we can't recover that lost form, enable prototype-based composition as Tucker wanted, and banish host objects to the ninth circle of hell, in a future edition. We can dream! :) ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: array like objects
On 15/12/2009, at 13:51, P T Withington wrote: (...) I once had the vain hope that I could say: function MyArray () {} MyArray.prototype = []; to create my own subclasses of Array. That might have lessened the need for isArrayLike. For that, we'd need an Array.create(). It might be a good thing... ¿? -- Jorge. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: array like objects
On Dec 15, 2009, at 4:51 AM, P T Withington wrote: On 2009-12-08, at 13:10, Mike Samuel wrote: All true. And yet it is not uncommon. See the bottom of this email for a quick survey of a number of libraries' uses of the array-like concept. FWIW, Here is the (separately/simultaneously invented) definition from OpenLaszlo: function isArrayLike (obj:*):Boolean { if (obj ((obj is Array) || (obj['length'] != (void 0 { ES4-ish is operator -- this must be LZX-JS? var ol = obj.length; return ((typeof(ol) == 'number' || ol is Number) ((ol|0) === ol) (ol = 0)); Could combine the last two using : js (-1|0)===-1 true js (-10)===-1 false } return false; } This only shows up in the debugger, and it is used to heuristicate when inspecting an object whether to portray it as an Array (possibly with non-numeric properties), or as an Object. It's an acknowledgement that users do create objects that they think of as arrays. OTOH, we don't do any magic beyond that. If a user intends an object to be treated as an array, they use Array operations on it (including `for`, not `for in`). I once had the vain hope that I could say: function MyArray () {} MyArray.prototype = []; to create my own subclasses of Array. That might have lessened the need for isArrayLike. If only internal methods were looked up by their (unnameable in the language [1]) names, instead of being accessed via [[Class]] (which is never delegated). Then lack of a custom [[Put]] in a (new MyArray) would let the prototype [[Put]] shine through, but receive the (new MyArray) instance as the object whose .length should be updated to be one greater than the highest index. But [[Class]] is a lightly abstracted vtable pointer; more's the pity. /be [1] http://wiki.ecmascript.org/doku.php?id=strawman:names ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: array like objects
On Dec 15, 2009, at 5:05 AM, Jorge Chamorro wrote: On 15/12/2009, at 13:51, P T Withington wrote: (...) I once had the vain hope that I could say: function MyArray () {} MyArray.prototype = []; to create my own subclasses of Array. That might have lessened the need for isArrayLike. For that, we'd need an Array.create(). It might be a good thing... ¿? What would Array.create do? Tucker is looking for a way to compose custom [[Put]] with prototype- based delegation. My reply suggested that if [[Put]] were a property name, just like length, and looked up along the prototype chain, so that the default [[Put]] was in Object.prototype, the custom Array [[Put]] that updates .length to be one greater than the highest index were on Array.prototype (or on [] in Tucker's example, but in general on the class prototype would suffice), etc., then we would not need anything new like Array.create. We would have one mechanism, prototype-based delegation, for finding methods (internal or external), and a complementary private-name scheme for generating and (implicitly, in the case of certain private names built into the language) using names that can't be expressed outside of an abstraction or module boundary. That still seems winning to me, but I didn't implement anything like it in 1995. It may have come up in ES1 days (I have vague memories), but no one implemented it so it was a dark horse for standardization. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: array like objects
On 15/12/2009, at 16:21, Brendan Eich wrote: On Dec 15, 2009, at 5:05 AM, Jorge Chamorro wrote: On 15/12/2009, at 13:51, P T Withington wrote: (...) I once had the vain hope that I could say: function MyArray () {} MyArray.prototype = []; to create my own subclasses of Array. That might have lessened the need for isArrayLike. For that, we'd need an Array.create(). It might be a good thing... ¿? What would Array.create do? Array.create(prototypeObject) would return an [] instance whose prototype chain's first object is prototypeObject. Currently, afaics, there's no way to do that (subclassing Array) not without resorting to .__proto__ or manually extending instances via own properties/methods. It's the same functionality provided by Object.create(), but for [] instead of {}. Tucker is looking for a way to compose custom [[Put]] with prototype-based delegation. My reply suggested that if [[Put]] were a property name, just like length, and looked up along the prototype chain, so that the default [[Put]] was in Object.prototype, the custom Array [[Put]] that updates .length to be one greater than the highest index were on Array.prototype (or on [] in Tucker's example, but in general on the class prototype would suffice), etc., then we would not need anything new like Array.create. The way I see it, the subclass' prototype object ought to come -necessarily- before the Array.prototype object in the subclassed instance's prototype chain. If not, every other existing and future [] instances would be affected too. Also, because if not there would be no way to create two different [] subclasses. If for some reason you wanted/needed to override/shadow any/some of Array.prototype's methods, isn't it that, in order to achieve that, the subclass' prototype object ought to come before the Array.prototype object in the instance's prototype chain ? That, or manually extending each and every instance with own properties ? AFAICS, anything that comes -in the prototype chain- after Array.prototype would extend all the [] instances at once. But most likely I'm missing something... We would have one mechanism, prototype-based delegation, for finding methods (internal or external), and a complementary private-name scheme for generating and (implicitly, in the case of certain private names built into the language) using names that can't be expressed outside of an abstraction or module boundary. That still seems winning to me, but I didn't implement anything like it in 1995. It may have come up in ES1 days (I have vague memories), but no one implemented it so it was a dark horse for standardization. Hmm. sorry, I don't quite follow. Cheers, -- Jorge. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: array like objects
On Dec 15, 2009, at 8:46 AM, Jorge Chamorro wrote: It's the same functionality provided by Object.create(), but for [] instead of {}. Ah, that helps -- thanks. This is not exactly what Tucker showed, though. Tucker is looking for a way to compose custom [[Put]] with prototype-based delegation. My reply suggested that if [[Put]] were a property name, just like length, and looked up along the prototype chain, so that the default [[Put]] was in Object.prototype, the custom Array [[Put]] that updates .length to be one greater than the highest index were on Array.prototype (or on [] in Tucker's example, but in general on the class prototype would suffice), etc., then we would not need anything new like Array.create. The way I see it, the subclass' prototype object ought to come - necessarily- before the Array.prototype object in the subclassed instance's prototype chain. If not, every other existing and future [] instances would be affected too. Also, because if not there would be no way to create two different [] subclasses. Sure. I was not describing Array.create or subclasses, just responding to what Tucker showed: function MyArray () {} MyArray.prototype = []; It may be that Array.create could fit his use-case instead, but if the idea is to make new user-defined *constructors* such as MyArray, then Array.create does not necessarily help. The user-defined constructor would have to return a new Array.create(MyArray.prototype) instance, and it would be stuck with the non-configurable own properties defined on Array instances. This might or might not be desired; anyway, it's not exactly the same as what you proposed in reply. If for some reason you wanted/needed to override/shadow any/some of Array.prototype's methods, isn't it that, in order to achieve that, the subclass' prototype object ought to come before the Array.prototype object in the instance's prototype chain ? I don't believe I wrote otherwise. That, or manually extending each and every instance with own properties ? AFAICS, anything that comes -in the prototype chain- after Array.prototype would extend all the [] instances at once. But most likely I'm missing something... My point was that if [[Put]], which is part of what makes an Array instance array-like, were delegated, along with the other internal methods in ES5 (which are of course specification devices, not concrete implementation artifacts), then what Tucker wrote -- exactly what he wrote -- would work. The reason it doesn't work is evident from a bit more REPL citing: js function MyArray () {} js MyArray.prototype = []; [] js var a = new MyArray js a.length 0 js a[9] = length should now be 10 length should now be 10 js a.length 0 What I proposed instead (not seriously; it's more a Self _homage_ than anything to add to a future JS/ES, at this point) was that setting a[9] would look for [[Put]] in a, not find it, look in a. [[Prototype]], which is [] above, not find a custom [[Put]], then look in [].[[Prototype]] which is Array.prototype, and finally find the ES- specified custom [[Put]] that advances length as needed. When the Array [[Put]] was invoked, it would be passed a as the directly referenced object, the receiver of the method call (aka | this|). Thus, 'length' would be set directly on a by the Array [[Put]] internal method. In ES specs and real implementations, internal methods and various corresponding implementation hooks are called based on [[Class]] of the directly referenced object, in contrast. No lookup for internal- method names that cannot be uttered in the source language is done. But this ancient design decision means we have host objects that can and do have inconsistent or even incorrect internal method suites. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: array like objects
Brendan Eich wrote: In ES specs and real implementations, internal methods and various corresponding implementation hooks are called based on [[Class]] of the directly referenced object, in contrast. In ES specs, there's no indication that [[Class]] can or should be used for internal method lookup; I don't know where you got that idea. As for implementation, [[Class]] could be derived from some other type tag that gives sufficient information to do such lookup, but [[Class]] by itself is not sufficient. -- David-Sarah Hopwood ⚥ http://davidsarah.livejournal.com signature.asc Description: OpenPGP digital signature ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: array like objects
On Dec 15, 2009, at 11:18 AM, David-Sarah Hopwood wrote: Brendan Eich wrote: In ES specs and real implementations, internal methods and various corresponding implementation hooks are called based on [[Class]] of the directly referenced object, in contrast. In ES specs, there's no indication that [[Class]] can or should be used for internal method lookup; I don't know where you got that idea. Sorry, I wrote called where I meant defined. In the ES specs, [[Class]] and internal methods are matched in invariant fashion, and the spec counts on this. ES1-3 throw TypeError from certain built-in methods if the |this| parameter's [[Class]] is not RegExp, e.g. ES5 Array.isArray of course checks [[Class]] directly. ES doesn't use [[Class]] much other than for TypeErrors and Object.prototype.toString, but it's aligned with the internal methods intentionally. This was a topic in ES1 days, based on C++ and C implementations. As for implementation, [[Class]] could be derived from some other type tag that gives sufficient information to do such lookup, but [[Class]] by itself is not sufficient. I'm not sure what you mean. Sure, [[Class]] in the spec is string- valued, so it can't be a vtable pointer. But in implementations that use C++, there is not only a class name-string associated with every instance, but a suite of internal methods or hooks. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: array like objects
Brendan Eich wrote: On Dec 15, 2009, at 11:18 AM, David-Sarah Hopwood wrote: Brendan Eich wrote: In ES specs and real implementations, internal methods and various corresponding implementation hooks are called based on [[Class]] of the directly referenced object, in contrast. [...] Sorry, I wrote called where I meant defined. As for implementation, [[Class]] could be derived from some other type tag that gives sufficient information to do such lookup, but [[Class]] by itself is not sufficient. I'm not sure what you mean. Sure, [[Class]] in the spec is string-valued, so it can't be a vtable pointer. But in implementations that use C++, there is not only a class name-string associated with every instance, but a suite of internal methods or hooks. Exactly: [[Class]] is associated with each instance and so are the other internal methods/properties, but that doesn't imply that other properties are defined based on [[Class]]. -- David-Sarah Hopwood ⚥ http://davidsarah.livejournal.com signature.asc Description: OpenPGP digital signature ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: array like objects
2009/12/13 Garrett Smith dhtmlkitc...@gmail.com: On Sun, Dec 13, 2009 at 10:31 AM, Mike Samuel mikesam...@gmail.com wrote: 2009/12/12 Garrett Smith dhtmlkitc...@gmail.com: On Sat, Dec 12, 2009 at 4:04 PM, Mark S. Miller erig...@google.com wrote: On Sat, Dec 12, 2009 at 3:38 PM, Garrett Smith dhtmlkitc...@gmail.com wrote: On Sat, Dec 12, 2009 at 2:59 PM, Mark S. Miller erig...@google.com wrote: Are we really this stuck? Can anyone think of a reliable, portable, and fast ES3R test that tests whether a property is enumerable, whether it is inherited or not? Not stuck. Why do you care if |length| is enumerable? If a standard |for| loop is used, it doesn't matter. Why anyone would want to use |for in| for something that is arrayLike? |for in| is not my concern. I wish a predicate that has little chance of false positives against legacy ES3 user constructed objects. Why the need to distinguish between a user-defined object that is intended for iteration vs one that is not? The program should already know. If the needs of a program are to iterate over an object's If programmers only wrote programs that would be true. But they also write libraries for consumption by other programmers, and many come from languages that encourage duck-typing : if it enumerates keys like a duck ... What well-designed piece of code has absolutely no idea what its input is? Noone is talking about code that has absolutely no idea what its inputs are. Please see my mail in this thread from 10:10 PST of 8 Dec for examples of code that knows that an input is either an array-like collection or a map-style collection but that use different definitions of the former. indexed properties, possibly filtering, mapping, etc, then allowing the algorithm to throw errors at Step 0 seems like a recipe for IE (a disaster). Please clarify a recipe for IE IE tends to take allowances for things whenever allowed to do so. Where the spec says implementation dependent, IE will do something either useless or harmful. ES5: | Whether the slice function can be applied successfully to | a host object is implementation-dependent. That note allows an implementation to throw an error if the thisArg is a Host object, without attempting to run the algorithm. That's a recipe for IE and IE is a disaster. I am suggesting a change so that an ES algorithm will run as specified. Other things IE will do is not implement, throw errors, or provide wacko results for [[HasProperty]], [[Get]], [[ToBoolean]] internal properties. It is worth noting that prior to ES5, this was allowable. Fortunately, ES5 rectified that with: | Every object (including host objects) must implement all | of the internal properties listed in Table 8. Which includes properties [[Get]], [[HasProperty]], et al. That is a change that I strongly endorse. Whether or not IE will change to comply with that requirement has yet to be seen. What IE should/does do seems orthogonal to what is array like and whether TC39 should comment on what is array like. [snip] I am still a bit fuzzy on what your arrayLike means or is intended for. Allen pointed out on previous thread[1] that Array generic methods provide an implicit contract. What that contract is depends on the method and arguments. It is meant to help library writers write generic code themselves that choose an appropriate iteration mechanism. I'm getting fuzzier. What is the method doing? Do you have a real example? Please see the mail mentioned above for examples of code, and please see Mark's mail from 11:12 PST 11 Dec for a proposed convention for array like. Garrett ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: array like objects
On Mon, Dec 14, 2009 at 9:34 AM, Mike Samuel mikesam...@gmail.com wrote: 2009/12/13 Garrett Smith dhtmlkitc...@gmail.com: On Sun, Dec 13, 2009 at 10:31 AM, Mike Samuel mikesam...@gmail.com wrote: 2009/12/12 Garrett Smith dhtmlkitc...@gmail.com: On Sat, Dec 12, 2009 at 4:04 PM, Mark S. Miller erig...@google.com wrote: On Sat, Dec 12, 2009 at 3:38 PM, Garrett Smith dhtmlkitc...@gmail.com wrote: On Sat, Dec 12, 2009 at 2:59 PM, Mark S. Miller erig...@google.com wrote: Are we really this stuck? Can anyone think of a reliable, portable, and fast ES3R test that tests whether a property is enumerable, whether it is inherited or not? Not stuck. Why do you care if |length| is enumerable? If a standard |for| loop is used, it doesn't matter. Why anyone would want to use |for in| for something that is arrayLike? |for in| is not my concern. I wish a predicate that has little chance of false positives against legacy ES3 user constructed objects. Why the need to distinguish between a user-defined object that is intended for iteration vs one that is not? The program should already know. If the needs of a program are to iterate over an object's If programmers only wrote programs that would be true. But they also write libraries for consumption by other programmers, and many come from languages that encourage duck-typing : if it enumerates keys like a duck ... What well-designed piece of code has absolutely no idea what its input is? Noone is talking about code that has absolutely no idea what its inputs are. Please see my mail in this thread from 10:10 PST of 8 Dec for examples of code that knows that an input is either an array-like collection or a map-style collection but that use different definitions of the former. You mentioned several code examples earlier: Please see the thread where I mentioned mired in the bowels of today's javascript libraries. Those examples are vague. They mostly try to address all possible cases, but don't do a very good job when the argument is a Host object. The fact that these things are considered reliable is an indication to the poor understanding of javascript. Take a snip from one of your shining examples: | dojo.isArray = function(/*anything*/ it){ | // summary: | // Return true if it is an Array. | // Does not work on Arrays created in other windows. | return it (it instanceof Array || typeof it == array); // Boolean | } That the method accepts *anything*' and returns anything. If - it - is falsy, such as (false, null, undefined, 0, ), then the inupt itself is returned. OTherwise there is a check to - it instanceof Array - which will always be false cross-frame/window. Third, there is typeof it == array, which will always be false. ALthough it is funny to see how many mistakes dojo can cram into a single line of code, the fact of the matter is that Dojo authors are not competent or knowledgeable of ECMAScript. Keep going? OK... | dojo.isArrayLike = function(/*anything*/ it){ |// summary: |// similar to dojo.isArray() but more permissive |// description: |// Doesn't strongly test for arrayness. |// Instead, settles for isn't a string or |// number and has a length property. |// Arguments objects and DOM collections |// will return true when passed to |// dojo.isArrayLike(), but will return false |// when passed to dojo.isArray(). |// returns: |// If it walks like a duck and quacks like a |// duck, return `true` |// return it it !== undefined // Boolean |// keep out built-in constructors (Number, String, ...) |// which have length properties. |!d.isString(it) !d.isFunction(it) |!(it.tagName it.tagName.toLowerCase() == 'form') |(d.isArray(it) || isFinite(it.length)); | } So we have a function which again takes *anything* and passes *anything* to d.isString d.isFunction which can be assumed to be similar in quality to their isArray function. Next, exclude any object that does has a tagName property form (case-insensitive). Finally, return true if d.isArray || isFinite(it.length). That includes textNodes, comment nodes, and probably a ton of other Host objects. The dojo.isArrayLike method tries to do something with anything, isn't very clear about what it does, and creates confusion by being posed as something competently written. Copying such things is obviously a poor idea. Basing APIs on such things is part of the death spiral. and I'm out of time. Regards, Garrett ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: array like objects
On Tue, Dec 15, 2009 at 6:29 AM, Mike Samuel mikesam...@gmail.com wrote: (3) If (!1), should future EcmaScript drafts define iteration order for arrays as index order and possibly recommend to array like host objects that the define iteration order similarly. I would suggest that this change would be mostly useless to me in my day to day work. The fact that past ecmascripts made the mistake of enumerating over properties that should not be enumerated over (such as monkey patched functions) is a fact of life that spawned two patterns: 1. The crockford iteration: for(var i in o) { if(o.hasOwnProperty(i)){ //iteration code } } 2. The array-like iteration: for(var i = 0; io.length; i++) { //iteration code } When I iterate over an array or array like, I want JUST the numbered indexes and none of the named indexes. I cannot think of a pattern that uses for( x in y) which can gaurantee that, and I can't figure out how I would use it in day to day work. The iteration code would need to be prepared for either a numeric i, or a string i, so I couldn't safely do arithmetic OR string operations on it without deciding which I was dealing with first. Even if I did so, I can't think of a situation where such code would be useful. not to mention, would not changing the order break compatibility with existing programs? A far more useful direction for iteration is the generalization of the forEach, map, and filter array extras. As others have pointed out, there is an implicit contract in these methods. These are methods that actually make programming easier, rather than just being useless appendixes like some rigging of for-in iteration order would be. I have no opinion on whether they should be static methods or not. My suggestion would be that if an object can function as the this argument within Array.prototype.slice, and slice returns a non empty array, then it is array like, and should be acceptable within any of the other array extras, as that's what I expect. This includes user defined objects such as the jQuery object, host collections, the arguments object, arrays from other frames, etc. This matches with patterns that I use, patterns used in jquery, the pattern of calling Array.prototype.slice on arguments objects, it renders moot the trouble with arrays from external frames, and so on. The only pitfall, which I've already pointed out, is that it also includes strings, and may, if naively defined ( as I did earlier) include functions, or objects in the style of {width:20, height:40: length:60}. When I write templating functions, or dom tree walking functions, I often need to distinguish between a host collection, an array or array like, and a string, to decide whether I simply pass the object on as is, or iterate over it. (is it singular or multiple in nature?) The fact is, javascript libraries, and programmers will use any language construct they can grab a hold of to make reasonable decisions that work within the program their writing. I'm not sure what value there would be in TC-39 decreeing a pattern as blessed, because programmers are just as likely to ignore it and just use what works for them, today, right now, no matter how technically wrong it is. However, the discussion here has revealed one interesting thing: Both ES3 and ES5 are inadequate for efficiently determining one particular property of an object that would be useful in the accuracy of these decisions. That is, it is difficult to determine whether an object has numeric properties or not without iterating over [length] elements. If there was some flag in an object that gets set on *insertion* of a numeric property, a flag which is observable in some way from user code, or something that gets observed by a built in isArrayLike, that would, I believe, close this gap. Does it make sense to try and unset the flag once it is set? I don't think that would be necessary. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: array like objects
2009/12/14 Breton Slivka z...@zenpsycho.com: On Tue, Dec 15, 2009 at 6:29 AM, Mike Samuel mikesam...@gmail.com wrote: (3) If (!1), should future EcmaScript drafts define iteration order for arrays as index order and possibly recommend to array like host objects that the define iteration order similarly. I would suggest that this change would be mostly useless to me in my day to day work. The fact that past ecmascripts made the mistake of enumerating over properties that should not be enumerated over (such as monkey patched functions) is a fact of life that spawned two patterns: 1. The crockford iteration: for(var i in o) { if(o.hasOwnProperty(i)){ //iteration code } } 2. The array-like iteration: for(var i = 0; io.length; i++) { //iteration code } Does the performance of this on large sparse arrays pose problems for you in your day to day work? E.g. for (o = new Array(1e100)). Do you use jquery in day to day work? I ask because that's one library that already seems to dynamically switch between the two. When I iterate over an array or array like, I want JUST the numbered indexes and none of the named indexes. I cannot think of a pattern that uses for( x in y) which can gaurantee that, and I can't figure out how I would use it in day to day work. The iteration code would need to be prepared for either a numeric i, or a string i, so I couldn't safely do arithmetic OR string operations on it without deciding which I was dealing with first. Even if I did so, I can't think of a situation where such code would be useful. not to mention, would not changing the order break compatibility with existing programs? Can you think of any existing programs that rely on the current (undefined but something like insertion order) order for arrays? A far more useful direction for iteration is the generalization of the forEach, map, and filter array extras. As others have pointed out, there is an implicit contract in these methods. These are methods that actually make programming easier, rather than just being useless appendixes like some rigging of for-in iteration order would be. I have no opinion on whether they should be static methods or not. My suggestion would be that if an object can function as the this argument within Array.prototype.slice, and slice returns a non empty I think basing the definition on what Array.prototype.slice does is a decent criterion. array, then it is array like, and should be acceptable within any of the other array extras, as that's what I expect. This includes user defined objects such as the jQuery object, host collections, the arguments object, arrays from other frames, etc. This matches with Only if those collections are not empty. Calling slice on an empty array obviously returns an empty array which would fail your test above. patterns that I use, patterns used in jquery, the pattern of calling Array.prototype.slice on arguments objects, it renders moot the trouble with arrays from external frames, and so on. The only pitfall, which I've already pointed out, is that it also includes strings, and may, if naively defined ( as I did earlier) include functions, or objects in the style of {width:20, height:40: length:60}. When I write templating functions, or dom tree walking functions, I often need to distinguish between a host collection, an array or array like, and a string, to decide whether I simply pass the object on as is, or iterate over it. (is it singular or multiple in nature?) The fact is, javascript libraries, and programmers will use any language construct they can grab a hold of to make reasonable decisions that work within the program their writing. I'm not sure what value there would be in TC-39 decreeing a pattern as blessed, because programmers are just as likely to ignore it and just use what works for them, today, right now, no matter how technically wrong it is. There are far fewer Javascript library writers than Javascript programmers so I'm not convinced that it's too large an audience to talk to. However, the discussion here has revealed one interesting thing: Both ES3 and ES5 are inadequate for efficiently determining one particular property of an object that would be useful in the accuracy of these decisions. That is, it is difficult to determine whether an object has numeric properties or not without iterating over [length] elements. If there was some flag in an object that gets set on *insertion* of a numeric property, a flag which is observable in some way from user code, or something that gets observed by a built in isArrayLike, that would, I believe, close this gap. Does it make sense to try and unset the flag once it is set? I don't think that would be necessary. This flag on insertion would again report that empty arrays are not array like, but I guess there's only one possible ordering of the elements of the empty set so it's moot.
Re: array like objects
On Tue, Dec 15, 2009 at 10:34 AM, Mike Samuel mikesam...@gmail.com wrote: 2009/12/14 Breton Slivka z...@zenpsycho.com: On Tue, Dec 15, 2009 at 6:29 AM, Mike Samuel mikesam...@gmail.com wrote: (3) If (!1), should future EcmaScript drafts define iteration order for arrays as index order and possibly recommend to array like host objects that the define iteration order similarly. I would suggest that this change would be mostly useless to me in my day to day work. The fact that past ecmascripts made the mistake of enumerating over properties that should not be enumerated over (such as monkey patched functions) is a fact of life that spawned two patterns: 1. The crockford iteration: for(var i in o) { if(o.hasOwnProperty(i)){ //iteration code } } 2. The array-like iteration: for(var i = 0; io.length; i++) { //iteration code } Does the performance of this on large sparse arrays pose problems for you in your day to day work? E.g. for (o = new Array(1e100)). No it does not. While I know that large sparse arrays are possible, I do not encounter them very often. The only time I've used a sparse array is in a representation of a timeline, where I did not expect to visit N indexes in greater than linear time. I would not consider this large on the order of your example, though. I have never encountered anything like that. My performance expectations are about the length of the array, not how many elements are properly stored in it. I lie a little bit here, there is one situation where I expect greater than linear time: Serializing the timeline into JSON, I convert the sparse array representation to an array like object representation before serializing (to save space). In this case I explicitly use for/in without identifying the type of the object first. I already have a reasonable assurance about what it's going to be since I created the object myself, it will either be an array, or undefined. I will concede though, a way to efficiently iterate over a sparse array in numeric order might be useful in some cases. I suggest the forEach (and other) array methods for this though. The efficiency and implementation of that does not have to be visible to the user, as long as the interface remains the same, and does not need to involve the ecmascript committee. Do you use jquery in day to day work? I ask because that's one library that already seems to dynamically switch between the two. Yes I do use jquery. I'm unsure about what you're referring to here when you say the two though. Can you think of any existing programs that rely on the current (undefined but something like insertion order) order for arrays? No I can't. I only know that standardising the order of iteration for objects was brought up as a compatiblity issue during the ES4/ES5 standardization process, since all popular interpreters behave in the same way. It would seem silly to me to then change the order after all that fuss. A far more useful direction for iteration is the generalization of the forEach, map, and filter array extras. As others have pointed out, there is an implicit contract in these methods. These are methods that actually make programming easier, rather than just being useless appendixes like some rigging of for-in iteration order would be. I have no opinion on whether they should be static methods or not. My suggestion would be that if an object can function as the this argument within Array.prototype.slice, and slice returns a non empty I think basing the definition on what Array.prototype.slice does is a decent criterion. array, then it is array like, and should be acceptable within any of the other array extras, as that's what I expect. This includes user defined objects such as the jQuery object, host collections, the arguments object, arrays from other frames, etc. This matches with Only if those collections are not empty. Calling slice on an empty array obviously returns an empty array which would fail your test above. I'm not married to the nonempty criterion. What I mean here is to exclude objects like {width:10, height:10, length:10}, or function objects. The non empty criterion is simply a heuristic, a naive solution to this tricky logic problem. But the empty set is still a set after all. I am open to better solutions, and I don't even mind considering such an object array like. I just thought I would try, out of consideration of the arguments of other posters. patterns that I use, patterns used in jquery, the pattern of calling Array.prototype.slice on arguments objects, it renders moot the trouble with arrays from external frames, and so on. The only pitfall, which I've already pointed out, is that it also includes strings, and may, if naively defined ( as I did earlier) include functions, or objects in the style of {width:20, height:40: length:60}. When I write templating functions, or dom tree walking functions, I often need
Re: array like objects
On Mon, Dec 14, 2009 at 11:29 AM, Mike Samuel mikesam...@gmail.com wrote: 2009/12/14 Garrett Smith dhtmlkitc...@gmail.com: On Mon, Dec 14, 2009 at 9:34 AM, Mike Samuel mikesam...@gmail.com wrote: 2009/12/13 Garrett Smith dhtmlkitc...@gmail.com: On Sun, Dec 13, 2009 at 10:31 AM, Mike Samuel mikesam...@gmail.com wrote: 2009/12/12 Garrett Smith dhtmlkitc...@gmail.com: On Sat, Dec 12, 2009 at 4:04 PM, Mark S. Miller erig...@google.com wrote: On Sat, Dec 12, 2009 at 3:38 PM, Garrett Smith dhtmlkitc...@gmail.com wrote: On Sat, Dec 12, 2009 at 2:59 PM, Mark S. Miller erig...@google.com wrote: Are we really this stuck? Can anyone think of a reliable, portable, and fast ES3R test that tests whether a property is enumerable, whether it is inherited or not? Not stuck. Why do you care if |length| is enumerable? If a standard |for| loop is used, it doesn't matter. Why anyone would want to use |for in| for something that is arrayLike? |for in| is not my concern. I wish a predicate that has little chance of false positives against legacy ES3 user constructed objects. Why the need to distinguish between a user-defined object that is intended for iteration vs one that is not? The program should already know. If the needs of a program are to iterate over an object's If programmers only wrote programs that would be true. But they also write libraries for consumption by other programmers, and many come from languages that encourage duck-typing : if it enumerates keys like a duck ... What well-designed piece of code has absolutely no idea what its input is? Noone is talking about code that has absolutely no idea what its inputs are. Please see my mail in this thread from 10:10 PST of 8 Dec for examples of code that knows that an input is either an array-like collection or a map-style collection but that use different definitions of the former. [...] That the method accepts *anything*' and returns anything. If - it - is Ok, so this goes back to your earlier strawman where you make the unsupported assertion that code that accepts *anything* is bad. Did I write that a method that accepts anything is bad? I wrote: | What well-designed piece of code has absolutely no idea what its input is? However if you want to argue that a function that is expected to accept *anything* is going to be without problems, the examples you provided don't go very far for support that. There is a reason I keep mentioning issue with IE's Host objects. The type of problem that would be solved by code that would be using an isArrayLike method might also be solved by a way to create *real* array from an object (host or native). In order to compare that to isArrayLike, there should be a problem where isArrayLike is a good solution. The code examples posted were believed to be demonstration of a need for isArrayLike, without having shown usage pattern. The posted code examples do not look like a good solution for *anything*. I would strongly discourage any web standard from taking influence from such pieces of code. By giving too much freedom with Host objects ECMAScript may be partly responsible for the allowance of this failure. What about the identity function, the cast operators defined in the standard (ToString, ToPrimitive, ToNumber, ToObject), operators like +, and some of your favorite array generics (Array.prototype.indexOf)? The more fundamental the operator, the fewer assumptions it can make about its inputs. I think I understood what you intended by cast operators, though nonstandard terminology can be the source of confusion. I have no idea what you are thinking the Identity function is. falsy, such as (false, null, undefined, 0, ), then the inupt itself is returned. That the author did not know this is an unsupported assertion and that this somehow makes the code bad is a non sequitur, but I'm not going to get sucked into a code purity pissing contest with you. The code you posted has the comment:- | If it walks like a duck and quacks like a duck, return `true` - so the author intends to return boolean, but instead returns 0, undefined, null, . I would not be surprised if the author actually does not know what his own code does. We also have the typeof it == array test, and so the author doesn't know the possible results for typeof, either. It is not a pissing contest; the code is far from being sufficient justification for any proposal. Most of the code in most of these libraries (Google closure, Dojo) is of poor quality. Please explain what this has to do with any of the following questions: (1) Should TC39 render an opinion on what is array like? (2) If (1), what is array like? What are you doing with it? (3) If (!1), should future EcmaScript drafts define iteration order for arrays as index order and possibly recommend to array like host objects that the define iteration order similarly. Why would you want that? So you can use for-in
Re: array like objects
On Dec 12, 2009, at 12:36 PM, Mark S. Miller wrote: On Sat, Dec 12, 2009 at 12:29 PM, Garrett Smith dhtmlkitc...@gmail.com wrote: Object.prototype.propertyIsEnumerable does not consider properties in the prototype chain. In effect, propertyIsEnumerable is a test to see if an object has *own* property that is also enumerable. And just when I was thinking I was finally beginning to understand this language :(. I wonder what other gotchas I'm still missing? See https://bugzilla.mozilla.org/show_bug.cgi?id=57048 filed by David Flanagan on 2000-10-17. My comment 11 is from 2000-12-01. This was an ES3 design-by-committee botch, never corrected. The spec originated the feature, no browser implemented anything like it first. SpiderMonkey tried doing it right as the bug shows, but no good deed goes unpunished. /be___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
RE: array like objects
David-Sarah Hopwood wrote: Mark S. Miller wrote: function isArrayLike(obj) { var len; return !!(obj typeof obj === 'object' 'length' in obj !({}).propertyIsEnumerable.call(obj, 'length') (len = obj.length) 0 === len); } If you want to avoid side effects: function isArrayLike(obj) { if (!obj || typeof obj !== 'object') return false; var desc = Object.getOwnPropertyDescriptor(obj, 'length'); if (desc) { var len = desc.value; return !desc.enumerable (len === undefined || len 0 === len); } } An advantage with Mark's code is that it doesn't rely on ES5 API. I think it's good to establish a standard for array-likeness that can be matched by ES3 code as well. Best regards Mike ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: array like objects
On Fri, Dec 11, 2009 at 12:08 PM, Mike Wilson mike...@hotmail.com wrote: Mark S. Miller wrote: If we're looking for a convention that is * does not admit any legacy ES3R non-array non-host objects (to prevent false positives) No native ES objects? * does easily allow ES5 programmers to define new array-like non-array objects * takes bounded-by-constant time (i.e., no iteration) *What* takes bounded-by-constant time? The object's existence would not take any time. * is a reasonably compatible compromise with the existing notions of array-like in legacy libraries as represented by previous examples in this thread Can you please clarify what the problem area is a little more? then I suggest: function isArrayLike(obj) { var len; return !!(obj typeof obj === 'object' 'length' in obj !({}).propertyIsEnumerable.call(obj, 'length') (len = obj.length) 0 === len); } Is looks like array like is defined as an an object where length is non-enumerable and numeric. What about [[Get]], [[HasProperty]] for numeric property names? And why must the - length - property be an *own* property? Why could length not be a getter in the prototype chain? Indeed many Mozilla DOM collections work this way: javascript: var cn = document.links; alert([cn.length, ({}).hasOwnProperty.call( cn, length)]); Mozilla elerts 80, false Garrett ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
RE: array like objects
Mark S. Miller wrote: On Sat, Dec 12, 2009 at 10:36 AM, Mike Samuel mikesam...@gmail.com wrote: On the String defect, we could repair that with ({}).toString.call(obj) !== '[object String]' Cons: An extra function call in the likely case Strings are arguable array-like Pros: Strings are inconsistently indexable : (new String('foo'))[0] is undefined on IE 6 Yes, this test would work. Before incorporating it, we should discuss whether String wrapper objects should indeed be considered array-like. My inclination is that they should not. Opinions? I don't think strings should trigger array-like, and this seems to be the position held by most JS libraries (see f ex dojo.isArrayLike). The normal use of these methods is to identify things like Arguments and NodeLists, ie sequences of distinct objects/values, not character sequences (text). Anyhow, whatever is decided here I think primitive strings and String wrappers should be handled the same way in this respect. Best regards Mike ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: array like objects
On Dec 12, 2009, at 11:36 AM, Mike Wilson wrote: Mark S. Miller wrote: On Sat, Dec 12, 2009 at 10:36 AM, Mike Samuel mikesam...@gmail.com wrote: On the String defect, we could repair that with ({}).toString.call(obj) !== '[object String]' Cons: An extra function call in the likely case Strings are arguable array-like Pros: Strings are inconsistently indexable : (new String('foo'))[0] is undefined on IE 6 Yes, this test would work. Before incorporating it, we should discuss whether String wrapper objects should indeed be considered array-like. My inclination is that they should not. Opinions? I don't think strings should trigger array-like, and this seems to be the position held by most JS libraries (see f ex dojo.isArrayLike). The normal use of these methods is to identify things like Arguments and NodeLists, ie sequences of distinct objects/values, not character sequences (text). A String object is indexable (to get unit-length strings -- not characters) with length as fencepost above the maximum index. A string or String object wrapping it has immutable .length and [i] for i length properties, OTOH -- it is not frozen, but this raises the question: is a frozen Array instance no longer array-like? Prototype's isArray wants 'splice' in obj 'join' in obj, but that rules out many objects considered array-like, without monkey-patching. We need a definition of array-like that matches common practice, if there is a common practice. Then we can see (without prejudgment) whether Strings satisfy it. From Mike Samuel's posts and my own quick reading, I don't see too much common practice. A more detailed survey of popular Ajax libraries would be great -- I'm out of time right now, but I'll try later today unless someone else does it first. Anyhow, whatever is decided here I think primitive strings and String wrappers should be handled the same way in this respect. Right. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: array like objects
On Dec 12, 2009, at 10:36 AM, Mike Samuel wrote: 2009/12/12 Mike Wilson mike...@hotmail.com: David-Sarah Hopwood wrote: Mark S. Miller wrote: function isArrayLike(obj) { var len; return !!(obj typeof obj === 'object' 'length' in obj !({}).propertyIsEnumerable.call(obj, 'length') (len = obj.length) 0 === len); } Nits: Array length is specified as being in [0, 0x8000_], Where? From the spec that implementors have had years to follow (citing ES3 rather than ES5), Array length is defined by: 15.4.5.2 length The length property of this Array object is always numerically greater than the name of every property whose name is an array index. which refers to the definition of array index here: 15.4 Array Objects Array objects give special treatment to a certain class of property names. 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 2^32−1. Every Array object has a length property whose value is always a nonnegative integer less than 2^32. So length is in [0, 0x] and array indexes are in [0, 0xfffe]. String length has no such constraint. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: array like objects
On Sat, Dec 12, 2009 at 12:01 PM, Mark S. Miller erig...@google.com wrote: On Sat, Dec 12, 2009 at 11:21 AM, Garrett Smith dhtmlkitc...@gmail.com wrote: On Fri, Dec 11, 2009 at 12:08 PM, Mike Wilson mike...@hotmail.com wrote: Mark S. Miller wrote: If we're looking for a convention that is * does not admit any legacy ES3R non-array non-host objects (to prevent false positives) No native ES objects? Native array and (currently) String wrapper objects do pass this test. No other ES3R natives objects can. Which native objects are you concerned about? Any user defined native object e.g. a jquery object or something like: { x : 10, length : 1.5 } * does easily allow ES5 programmers to define new array-like non-array objects * takes bounded-by-constant time (i.e., no iteration) *What* takes bounded-by-constant time? The object's existence would not take any time. The execution time of this predicate. Actually, that's not necessarily true. [snip] Got it. That means that the isArrayLike test itself is constant time. That makes sense. * is a reasonably compatible compromise with the existing notions of array-like in legacy libraries as represented by previous examples in this thread Can you please clarify what the problem area is a little more? then I suggest: function isArrayLike(obj) { var len; return !!(obj typeof obj === 'object' 'length' in obj !({}).propertyIsEnumerable.call(obj, 'length') (len = obj.length) 0 === len); } [snip] Is looks like array like is defined as an an object where length is non-enumerable and numeric. What about [[Get]], [[HasProperty]] for numeric property names? And why must the - length - property be an *own* property? Why could length not be a getter in the prototype chain? Indeed many Mozilla DOM collections work this way: javascript: var cn = document.links; alert([cn.length, ({}).hasOwnProperty.call( cn, length)]); Mozilla elerts 80, false Not a problem. The proposed predicate does not test whether 'length' is own, only whether it is enumerable. A squarefree session on FF 3.5.5: [snip] Ah no, that is not correct, your isArrayLike *does* test to see whether length is own. Object.prototype.propertyIsEnumerable does not consider properties in the prototype chain. In effect, propertyIsEnumerable is a test to see if an object has *own* property that is also enumerable. We discussed this back in ES4 proposal days, and I think I remember that it was decided to keep the existing behavior (as unintuitive as it may be) to not break existing code (some already broken things YUI and some other libs were doing). Also notice that the name propertyIsEnumerable deviates from standard boolean predicate method naming convention. Flash AS apparently has an isPropertyEnumerable (more standard boolean predicate name). Garrett ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: array like objects
On Sat, Dec 12, 2009 at 12:29 PM, Garrett Smith dhtmlkitc...@gmail.comwrote: Object.prototype.propertyIsEnumerable does not consider properties in the prototype chain. In effect, propertyIsEnumerable is a test to see if an object has *own* property that is also enumerable. And just when I was thinking I was finally beginning to understand this language :(. I wonder what other gotchas I'm still missing? -- Cheers, --MarkM ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: array like objects
On Sat, Dec 12, 2009 at 12:29 PM, Garrett Smith dhtmlkitc...@gmail.com wrote: Object.prototype.propertyIsEnumerable does not consider properties in the prototype chain. In effect, propertyIsEnumerable is a test to see if an object has *own* property that is also enumerable. At the end of http://wiki.ecmascript.org/doku.php?id=conventions:isarraylike I have added the issue: Unfortunately, the propertyIsEnumerable test above, despite the name, actually tests whether a property is both enumerable and own. This means the above predicate will reject objects that inherit a non-enumerable length property. I can think of no reliable and portable ES3R test which tests only property enumerability, except by running a for-in loop and testing the output. Doing so would kill the bounded-by-constant time virtue. Are we really this stuck? Can anyone think of a reliable, portable, and fast ES3R test that tests whether a property is enumerable, whether it is inherited or not? -- Cheers, --MarkM ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: array like objects
On Sat, Dec 12, 2009 at 3:38 PM, Garrett Smith dhtmlkitc...@gmail.comwrote: On Sat, Dec 12, 2009 at 2:59 PM, Mark S. Miller erig...@google.com wrote: Are we really this stuck? Can anyone think of a reliable, portable, and fast ES3R test that tests whether a property is enumerable, whether it is inherited or not? Not stuck. Why do you care if |length| is enumerable? If a standard |for| loop is used, it doesn't matter. Why anyone would want to use |for in| for something that is arrayLike? |for in| is not my concern. I wish a predicate that has little chance of false positives against legacy ES3 user constructed objects. If var obelisk = { width: 9, length: 16, height: 25 }; appears in some existing code, I don't want a predicate that decides the obelisk is array-like, as it was clearly not the intent. The reason I care about enumerability is that legacy ES3R code has no way to create an ordinary native object with a non-enumerable length property, thereby preventing false positives in against legacy ES3R objects. OTOH, your examples of false DOM negatives below are sufficiently discouraging that perhaps this whole exercise is fruitless. Perhaps there is no coherent notion of array-like to be rescued from current practice. Can an arrayLike object have other properties? If you're talking about a DOM collection, you can be that it will have other properties and probably a mix of enumerable and non-enumerable proprietary properties. A DOM collection (NodeList, for example) might very well have a length property that shows up in the body of a for in loop. There is no standard that specifies one way or another if a NodeList's length property should be enumerable. I can't see why anyone would care, either. javascript: for(var p in document.childNodes) if(!isFinite(p)) alert(p); Firefox 3.5, Safari 4, Chrome 2: length item Opera 10: length item namedItem tags IE7 tags That example alone shows a few good reasons why using a for in loop would be a bad choice. In superficial testing in a few browsers, the length property showed up in the body of a for in loop. Other properties will show up, depending on the implementation and property name. Other collections will likely have even more properties. if a DOM collection is considered arrayLike, then using for in loops over arrayLike can be considered to be a reckless, error-prone concept. OTOH, If indexed properties are got off the object, as with your standard for loop, the enumerability of - length - is irrelevant. So again: Why do you care if |length| is enumerable? Garrett ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss -- Cheers, --MarkM ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: array like objects
2009/12/12 Brendan Eich bren...@mozilla.com: On Dec 12, 2009, at 10:36 AM, Mike Samuel wrote: 2009/12/12 Mike Wilson mike...@hotmail.com: David-Sarah Hopwood wrote: Mark S. Miller wrote: function isArrayLike(obj) { var len; return !!(obj typeof obj === 'object' 'length' in obj !({}).propertyIsEnumerable.call(obj, 'length') (len = obj.length) 0 === len); } Nits: Array length is specified as being in [0, 0x8000_], Where? From the spec that implementors have had years to follow (citing ES3 rather than ES5), Array length is defined by: 15.4.5.2 length The length property of this Array object is always numerically greater than the name of every property whose name is an array index. which refers to the definition of array index here: 15.4 Array Objects Array objects give special treatment to a certain class of property names. 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 2^32−1. Every Array object has a length property whose value is always a nonnegative integer less than 2^32. So length is in [0, 0x] and array indexes are in [0, 0xfffe]. Ah. Thanks. String length has no such constraint. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: array like objects
2009/12/12 Garrett Smith dhtmlkitc...@gmail.com: On Fri, Dec 11, 2009 at 12:08 PM, Mike Wilson mike...@hotmail.com wrote: Mark S. Miller wrote: If we're looking for a convention that is * does not admit any legacy ES3R non-array non-host objects (to prevent false positives) No native ES objects? * does easily allow ES5 programmers to define new array-like non-array objects * takes bounded-by-constant time (i.e., no iteration) *What* takes bounded-by-constant time? The object's existence would not take any time. * is a reasonably compatible compromise with the existing notions of array-like in legacy libraries as represented by previous examples in this thread Can you please clarify what the problem area is a little more? then I suggest: function isArrayLike(obj) { var len; return !!(obj typeof obj === 'object' 'length' in obj !({}).propertyIsEnumerable.call(obj, 'length') (len = obj.length) 0 === len); } Is looks like array like is defined as an an object where length is non-enumerable and numeric. What about [[Get]], [[HasProperty]] for numeric property names? I prefer integral and non-negative to numeric. As Brendan pointed out, the definition of uint32 already matches up with length as specified for arrays. He also points out that there in no limit on string length, but if ulp(length) 1 then you run into a lot of problems, so there is a practical limit on length of 2**53. I think any of the following definitions of length would be fine * uint32: (x === (x 0) isFinite(x)) * non-negative integer: (x === +x !(x % 1)) * non-negative integer i such that ulp(i) = 1: (x === +x !(x % 1) (x - -1) !== x) And why must the - length - property be an *own* property? Why could length not be a getter in the prototype chain? Indeed many Mozilla DOM collections work this way: javascript: var cn = document.links; alert([cn.length, ({}).hasOwnProperty.call( cn, length)]); Mozilla elerts 80, false Garrett ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: array like objects
On Sat, Dec 12, 2009 at 4:04 PM, Mark S. Miller erig...@google.com wrote: On Sat, Dec 12, 2009 at 3:38 PM, Garrett Smith dhtmlkitc...@gmail.com wrote: On Sat, Dec 12, 2009 at 2:59 PM, Mark S. Miller erig...@google.com wrote: Are we really this stuck? Can anyone think of a reliable, portable, and fast ES3R test that tests whether a property is enumerable, whether it is inherited or not? Not stuck. Why do you care if |length| is enumerable? If a standard |for| loop is used, it doesn't matter. Why anyone would want to use |for in| for something that is arrayLike? |for in| is not my concern. I wish a predicate that has little chance of false positives against legacy ES3 user constructed objects. Why the need to distinguish between a user-defined object that is intended for iteration vs one that is not? The program should already know. If the needs of a program are to iterate over an object's indexed properties, possibly filtering, mapping, etc, then allowing the algorithm to throw errors at Step 0 seems like a recipe for IE (a disaster). [snip] I am still a bit fuzzy on what your arrayLike means or is intended for. Allen pointed out on previous thread[1] that Array generic methods provide an implicit contract. What that contract is depends on the method and arguments. Array.prototype.slice, when supplied with one argument, has the following implicit contract for the thisArg: 1) [[Get]] 2) [[HasProperty]] checks An object that can do those two, but also has a - length - property has enough functionality so that a call to - ([]).slice.call( anObject ) - would be expected to return an array that has anObject's numeric properties, except for the specification allowing anything goes with Host object and we see JScript Object Expected errors in IE. Allen has not yet commented on that. Stronger wording for Host object in ES specification would provide stronger incentive for implementations (IE) to use host objects that have consistent functionality. IOW, if the Array.prototype.slice says: | 2. Call the [[Get]] method of this object with argument length. [[Get]] works via property accessor operators, as in:- k = anObject.length 0; - then that step of the algorithm should succeed. Once an Array is obtained, then the program can use the other Array.prototype methods on that object. Alternatively, if the object's functionality is known by the programmer and the functionality fulfills an implicit contract for a generic method, then the program should be able to use that method, host object or not. At least, I would like it to be that way. | var anObject = document.body.childNodes; | function fn( obj ) { return /foo/.test(obj.className); }; | Array.prototype.filter.call( anObject, fn ); Or (Spidermonkey only): | function fn( obj ) { return /foo/.test(obj.className); } | Array.filter( document.body.childNodes, fn ); ES5 allows the algorithm to terminate at step 0, so that approach is not viable. A for loop could be used, however the downside to that now the program uses a user-defined makeArray function. makeArray( anObject ). filter( function(obj) { return /foo/.test(obj.className); }); Which requires double iteration over the collection, plus the overhead of an extra call, plus the extra makeArray function, downloaded and interpreted and loaded in memory. This sort of thing is often mired in the bowels of today's popular libraries. In contrast, the generic algorithm in question could be specified to execute each step, regardless of whether or not the argument is a host object. Whether or not the execution of that step results in error depends on the particular object's implementation. This way, if an object supports [[Get]], an Array method that calls [[Get]] could be expected to succeed. However if the object has a readonly - length - property, or - length - is a getter with no setter, then it would be expected to throw an error. Is this idea reasonable or feasable, from a spec standpoint or implementation standpoint? This is a very very old issue these errors are still coming in IE8, but do not appear in other major browsers (AFAIK). Is stronger wording for host objects a good idea? Garrett [1]https://mail.mozilla.org/pipermail/es-discuss/2009-May/009310.html [2]https://mail.mozilla.org/pipermail/es-discuss/2009-December/010241.html ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
RE: array like objects
I think Breton mentions something important here; the desire to actually detect if something is an array or arraylike to be able to branch to different code that does completely different things for array[likes] and objects. If we just provide a better generic iteration construct then this part is lost, as I might even not be doing iteration in one of the branches. Certainly, solving this isn't easy, but it would be good if there was some direction taken by the WG to provide a standard way to detect arraylikeness without having to do iteration, so JS runtimes, browser host objects and JS libraries can follow this precedent. Best regards Mike Wilson Breton Slivka wrote: On Tue, Dec 8, 2009 at 1:29 PM, Breton Slivka z...@zenpsycho.com wrote: The one that I use is function isArrayLike(i){ return (typeof i !==string) i.length !== void (0); } It might not be perfect, but it allows me to make certain assumptions about the input that are useful enough. Keep in mind that an Array may have a length of 5, and all those values are undefined, so {length:4} could be used as a valid arrayLike, and that seems reasonable to me. On Tue, Dec 8, 2009 at 1:18 PM, Allen Wirfs-Brock allen.wirfs-br...@microsoft.com wrote: Curiously, I don't believe any of the generic functions for arrays and array-like objects in section 15.4.4 actually depend upon such an array-like test. They all simply use ToUint32 applied to the value of the length property. If the length property doesn't exist or its value isn't something that an a convertible representation of a number, the value 0 is used as the length and not much happens. By this definition, all objects are essentially array-like but many have no array-like elements. You've encapsulated here some of the reasoning behind my earlier test- Anything that passes my test is acceptable to any of the array prototype functions, but filters out two situations that I've found I didn't intend an object to be treated as an array. My usecase is overloaded functions that may also accept objects, and strings, and arraylikes, but I want a way to distinguish array-likes from objects and strings. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: array like objects
On Fri, Dec 11, 2009 at 2:27 AM, Mike Wilson mike...@hotmail.com wrote: I think Breton mentions something important here; the desire to actually detect if something is an array or arraylike to be able to branch to different code that does completely different things for array[likes] and objects. If we just provide a better generic iteration construct then this part is lost, as I might even not be doing iteration in one of the branches. Certainly, solving this isn't easy, but it would be good if there was some direction taken by the WG to provide a standard way to detect arraylikeness without having to do iteration, so JS runtimes, browser host objects and JS libraries can follow this precedent. If we're looking for a convention that is * does not admit any legacy ES3R non-array non-host objects (to prevent false positives) * does easily allow ES5 programmers to define new array-like non-array objects * takes bounded-by-constant time (i.e., no iteration) * is a reasonably compatible compromise with the existing notions of array-like in legacy libraries as represented by previous examples in this thread then I suggest: function isArrayLike(obj) { var len; return !!(obj typeof obj === 'object' 'length' in obj !({}).propertyIsEnumerable.call(obj, 'length') (len = obj.length) 0 === len); } Since getting 'length' may have side effects, this is written a bit weird so that this get only happens after earlier tests pass. And yes, I'm aware that this usage of Object.prototype.propertyIsEnumerable implies that catchalls must virtualize it in order for a proxy to be able to pass this test :(. -- Cheers, --MarkM ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: array like objects
[+commonjs] On Fri, Dec 11, 2009 at 12:08 PM, Mike Wilson mike...@hotmail.com wrote: Thanks Mark, this is the right way to approach it I think. String objects will be considered array-like above which may not be desired, but either way, I think it is this type of guideline that can prove valuable, so host objects and libraries can make sure to adhere (or make sure not to adhere) to that pattern. I'm not sure where it should be put, but maybe there should be an official ES duck page with committee approved patterns ;-). I like the idea of collecting consensus patterns for coordinating conventions outside the jurisdiction of the specs. I wonder whether this is best done at wiki.ecmascript.org or at wiki.commonjs.org ? The CommonJS community is already functioning as an informal open standards body for such conventions. -- Cheers, --MarkM ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: array like objects
Mark S. Miller wrote: On Fri, Dec 11, 2009 at 2:27 AM, Mike Wilson mike...@hotmail.com wrote: I think Breton mentions something important here; the desire to actually detect if something is an array or arraylike to be able to branch to different code that does completely different things for array[likes] and objects. [...] If we're looking for a convention that is * does not admit any legacy ES3R non-array non-host objects (to prevent false positives) * does easily allow ES5 programmers to define new array-like non-array objects * takes bounded-by-constant time (i.e., no iteration) * is a reasonably compatible compromise with the existing notions of array-like in legacy libraries as represented by previous examples in this thread then I suggest: function isArrayLike(obj) { var len; return !!(obj typeof obj === 'object' 'length' in obj !({}).propertyIsEnumerable.call(obj, 'length') (len = obj.length) 0 === len); } Since getting 'length' may have side effects, this is written a bit weird so that this get only happens after earlier tests pass. If you want to avoid side effects: function isArrayLike(obj) { if (!obj || typeof obj !== 'object') return false; var desc = Object.getPropertyDescriptor(obj, 'length'); if (desc) { var len = desc.value; return !desc.enumerable (len === undefined || len 0 === len); } } This allows any length getter without checking that it will return an array index, but it still satisfies all of the above requirements. However, I don't see why the check on the current value of length is necessary. For it to make any difference, there would have to be a *nonenumerable* length property on a non-function object, with a value that is not an array index. How and why would that happen? And yes, I'm aware that this usage of Object.prototype.propertyIsEnumerable implies that catchalls must virtualize it in order for a proxy to be able to pass this test :(. Same with Object.getPropertyDescriptor in the above. -- David-Sarah Hopwood ⚥ http://davidsarah.livejournal.com signature.asc Description: OpenPGP digital signature ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: array like objects
2009/12/8 Mike Samuel mikesam...@gmail.com: It occurred to me after looking at the proxy strawman that it might help to nail down what array-like means in future drafts. It isn't directly related to the proxy stuff though so I thought I'd start a separate thread. I've seen quite a bit of library code that does something like if (isArrayLike(input)) { // iterate over properties [0,length) in increasing order } else { // Iterate over key value pairs } This looks fairly broken to me. If the object has enumerable properties that aren't positive integers then they don't get iterated over just because some heuristic says it's array-like. If the heuristic says it's array-like then we iterate over portentially billions of indexes even if it is very sparse. I think there are two different questions being asked here. 1) Does the object have the special semantics around .length? This is potentially useful to know and the normal way to find out doesn't work. Instanceof is affected by setting __proto__, yet the special .length handling persists and instanceof doesn't work for cross-iframe objects. 2) Is it more efficient to iterate over this object with for-in or is it more efficient (and sufficient) to iterate with a loop from 0 to length-1? You can't implement functions like slice properly without this information and there's no way to get it. but different libraries defined array-like in different ways. Some ways I've seen: (1) input instanceof Array (2) Object.prototype.toString(input) === '[object Array]' (3) input.length === (input.length 0) etc. These all look like failed attempts to answer one or both of the two questions above. The common thread with array like objects is that they are meant to be iterated over in series. It might simplify library code and reduce confusion among clients of these libraries if there is some consistent definition of series-ness. This committee might want to get involved since it could affect discussions on a few topics: (1) key iteration order (2) generators/iterators (3) catchall proposals (4) type systems One strawman definition for an array like object: o is an array like object if o[[Get]]('length') returns a valid array index or one greater than the largest valid array index. The need to distinguish between the two in library code could be mooted if for (in) on arrays iterated over the array index properties of arrays in numeric oder order first, followed by other properties in insertion order, and host objects like NodeCollections followed suit. FWIW V8 does this for both arrays and objects. But really for..in is pretty sick for arrays. It will convert every single index in the array to a string. That's not something to be encouraged IMHO. -- Erik Corry ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: array like objects
2009/12/8 Erik Corry erik.co...@gmail.com: 2009/12/8 Mike Samuel mikesam...@gmail.com: It occurred to me after looking at the proxy strawman that it might help to nail down what array-like means in future drafts. It isn't directly related to the proxy stuff though so I thought I'd start a separate thread. I've seen quite a bit of library code that does something like if (isArrayLike(input)) { // iterate over properties [0,length) in increasing order } else { // Iterate over key value pairs } This looks fairly broken to me. If the object has enumerable properties that aren't positive integers then they don't get iterated over just because some heuristic says it's array-like. If the heuristic says it's array-like then we iterate over portentially billions of indexes even if it is very sparse. All true. And yet it is not uncommon. See the bottom of this email for a quick survey of a number of libraries' uses of the array-like concept. I think there are two different questions being asked here. 1) Does the object have the special semantics around .length? This is potentially useful to know and the normal way to find out doesn't work. Instanceof is affected by setting __proto__, yet the special .length handling persists and instanceof doesn't work for cross-iframe objects. I think I agree with the bit about length, but __proto__ doesn't work on non mozilla interpreters and isn't likely to be standardized. I don't see how it's relevant to array-like-ness. 2) Is it more efficient to iterate over this object with for-in or is it more efficient (and sufficient) to iterate with a loop from 0 to length-1? You can't implement functions like slice properly without this information and there's no way to get it. Efficiency is obviously important, but another important distinction is whether 'length' should be included in the set of keys iterated over, and whether iteration over array-index keys should be in numeric order. but different libraries defined array-like in different ways. Some ways I've seen: (1) input instanceof Array (2) Object.prototype.toString(input) === '[object Array]' (3) input.length === (input.length 0) etc. These all look like failed attempts to answer one or both of the two questions above. Agreed. Some more attempts below. The common thread with array like objects is that they are meant to be iterated over in series. It might simplify library code and reduce confusion among clients of these libraries if there is some consistent definition of series-ness. This committee might want to get involved since it could affect discussions on a few topics: (1) key iteration order (2) generators/iterators (3) catchall proposals (4) type systems One strawman definition for an array like object: o is an array like object if o[[Get]]('length') returns a valid array index or one greater than the largest valid array index. The need to distinguish between the two in library code could be mooted if for (in) on arrays iterated over the array index properties of arrays in numeric oder order first, followed by other properties in insertion order, and host objects like NodeCollections followed suit. FWIW V8 does this for both arrays and objects. But really for..in is pretty sick for arrays. It will convert every single index in the array to a string. That's not something to be encouraged IMHO. Also agreed. -- Erik Corry Prototype.js dodges this problem by adding an each method to Array.prototype and others. This obviously fails for cross-context Arrays, and also suffers from the large sparse array and missing non-array-index properties problems. It does switch on arrays in places, and does so inconsistently though -- in one case (unnecessarily?) filtering out arguments objects? if (Object.isArray(item) !('callee' in item)) { for (var j = 0, arrayLength = item.length; j arrayLength; j++) array.push(item[j]); } else { function flatten() { return this.inject([], function(array, value) { if (Object.isArray(value)) return array.concat(value.flatten()); array.push(value); return array; dojo.clone does if(d.isArray(o)){ r = []; for(i = 0, l = o.length; i l; ++i){ if(i in o){ r.push(d.clone(o[i])); } } }else{ // generic objects r = o.constructor ? new o.constructor() : {}; } dojo.isArray = function(/*anything*/ it){ // summary: // Return true if it is an Array. // Does not work on Arrays created in other windows. return it (it instanceof Array || typeof it ==
Re: array like objects
On Dec 8, 2009, at 1:10 PM, Mike Samuel wrote: 2009/12/8 Erik Corry erik.co...@gmail.com: 2009/12/8 Mike Samuel mikesam...@gmail.com: It occurred to me after looking at the proxy strawman that it might help to nail down what array-like means in future drafts. It isn't directly related to the proxy stuff though so I thought I'd start a separate thread. I've seen quite a bit of library code that does something like if (isArrayLike(input)) { // iterate over properties [0,length) in increasing order } else { // Iterate over key value pairs } This looks fairly broken to me. If the object has enumerable properties that aren't positive integers then they don't get iterated over just because some heuristic says it's array-like. If the heuristic says it's array-like then we iterate over portentially billions of indexes even if it is very sparse. All true. And yet it is not uncommon. See the bottom of this email for a quick survey of a number of libraries' uses of the array-like concept. [...] Prototype.js dodges this problem by adding an each method to Array.prototype and others. This obviously fails for cross-context Arrays, and also suffers from the large sparse array and missing non-array-index properties problems. It does switch on arrays in places, and does so inconsistently though -- in one case (unnecessarily?) filtering out arguments objects? If you look just a bit below those lines, you will see that this whole `concat` method is only assigned to `Array.prototype.concat` when `CONCAT_ARGUMENTS_BUGGY` is truthy. `CONCAT_ARGUMENTS_BUGGY` feature test looks like this: (function() { return [].concat(arguments)[0][0] !== 1; })(1,2); and is essentially a workaround to an issue with Opera, which, contrary to specs, makes `arguments instanceof Array`, yet fails to implement proper `concat` algorithm for arguments (as feature test demonstrates). As far as `isArray` in Prototype.js, we just test for [[Class]] === Array (which is good across frames, but still fails across windows in IE). There's, of course, no silver bullet `isArray` solution for a library. It's all about specific requirements, and as long as users do not fully understand language specifics, there will be broken expectations; some will expect arrays to inherit from `Array.prototype` (and so have any of `Array.prototype` methods available); some will expect arrays to have special [[Put]] and `length`behavior; and others will expect array-like host objects (that neither inherit from Array, nor have special [[Put]] or [[Class]] === Array) to be considered arrays as well. It's all about context ;) [...] -- kangax ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: array like objects
Ok, let's think about a new loop construct. Adding new syntax makes for-in a boat-anchor implementations lug around, in the best case. But realistically it will be years before developers can count on the new loop construct. And as support comes online, developers will have to choose which to use, and people learning JS will have to cope with two similar kinds of loops. Migration involves either a translator, or writing loops twice (a non- starter in practice), or using a source to source translator. This all costs. It seems to me that the possibility of breakage under opt-in versioning is not worse than the costs listed above. But again, I welcome *real-world* examples (your example indicts polymorphic + as much as string-ifying for-in, but no one is proposing a new concat operator :-P) Opt-in versioning will introduce new keywords including let and possibly yield, which constitute breaking changes. We know this from reality-based testing (Firefox 2 betas, JS1.7). While we haven't tried leaving for-in-iterated indexes as numbers in years (we used to, since ES1 made the change but Netscape's implementation did not for a while), I suspect the breaking-ness is less than the new-keywords- under-opt-in issue. But we are introducing new keywords, they're reserved in ES5 strict. So I'll poke around with Google codesearch a bit later today. /be On Dec 8, 2009, at 11:18 AM, Allen Wirfs-Brock wrote: -Original Message- From: es-discuss-boun...@mozilla.org [mailto:es-discuss-boun...@mozilla.org ] On Behalf Of Brendan Eich ... If anyone knows of real-world code that would be broken by the type of the for-in loop variable not always being string, I'm all ears. /be I don't have a real world example or a compelling use case for the following, but it seems like it might (possibly inadvertently) occur on the web: One place it makes a difference is if the + operator is used with the induction variable: var a=[0,2,1]; var b=[]; for (var i in a) b[i+1] = a[i]; In ES3/5, b will end up with properties named '01', '11', '21' and length=22. Note that '01' is not an array index because of the leading '0'. If for-in was changed so that i has numeric values for array index property names then b would end up with property names '1','2','3', and length=4. The changed behavior is probably(??) what would be intended by somebody who did this, but changing it might still break apps that are currently perceived to be working. My personal feeling is that rather than trying to fix various things about for-in (including pinning down enumeration order) it would be better to introduce a new more carefully defined enumeration statement(s) (for keys/for values??) and leave for-in alone. Allen ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: array like objects
2009/12/8 Brendan Eich bren...@mozilla.com: On Dec 8, 2009, at 10:10 AM, Mike Samuel wrote: 1) Does the object have the special semantics around .length? This is potentially useful to know and the normal way to find out doesn't work. Instanceof is affected by setting __proto__, yet the special .length handling persists and instanceof doesn't work for cross-iframe objects. I think I agree with the bit about length, but __proto__ doesn't work on non mozilla interpreters WebKit JSC implemented too :-/. and isn't likely to be standardized. You got that part right :-). I don't see how it's relevant to array-like-ness. Agreed, but Erik's point here was about instanceof. Not only mutable __proto__, but mutable bindings for constructors, and the issue of multiple global objects with their unrelated suites of builtin constructors, make instanceof less than ideal for deciding array-like. Ah ok. I agree with Erik then. Even moreso, instanceof doesn't work cross context. Efficiency is obviously important, but another important distinction is whether 'length' should be included in the set of keys iterated over, In ES1-5, length is not enumerable for Array, String, and arguments objects. Anything array-like, same deal or it's not like enough. Maybe I'm imagining things, but I'm pretty sure that on some browsers length is enumerable on arr in var arr = [1,2,3] arr.length = 2; and whether iteration over array-index keys should be in numeric order. I'm suspicious of real code depending on insertion order. Typically arrays are built front to back so the two are the same. Exceptional cases may break existing for-in loops that inspect arrays and want numeric order. This is something to investigate (google codesearch?). But really for..in is pretty sick for arrays. It will convert every single index in the array to a string. That's not something to be encouraged IMHO. Also agreed. Yes, that is an ES1 change from my Netscape implementation. It is costly enough that optimizing implementations use memoized or static strings for small integer literals! Yet for-in on an array-like is attractive, especially in light of comprehensions and generator expressions. One way forward would be to change to number type under opt-in Harmony versioning. Another option is new syntax, but that requires opt-in versioning anyway, and it's not clear to me that changing for-in on Arrays, or on all array-likes, to return numbers for indexes, is an incompatibility that we could not get away with. If anyone knows of real-world code that would be broken by the type of the for-in loop variable not always being string, I'm all ears. /be -- Erik Corry Prototype.js dodges this problem by adding an each method to Array.prototype and others. This obviously fails for cross-context Arrays, and also suffers from the large sparse array and missing non-array-index properties problems. It does switch on arrays in places, and does so inconsistently though -- in one case (unnecessarily?) filtering out arguments objects? if (Object.isArray(item) !('callee' in item)) { for (var j = 0, arrayLength = item.length; j arrayLength; j++) array.push(item[j]); } else { function flatten() { return this.inject([], function(array, value) { if (Object.isArray(value)) return array.concat(value.flatten()); array.push(value); return array; dojo.clone does if(d.isArray(o)){ r = []; for(i = 0, l = o.length; i l; ++i){ if(i in o){ r.push(d.clone(o[i])); } } }else{ // generic objects r = o.constructor ? new o.constructor() : {}; } dojo.isArray = function(/*anything*/ it){ // summary: // Return true if it is an Array. // Does not work on Arrays created in other windows. return it (it instanceof Array || typeof it == array); // Boolean } dojo.isArrayLike = function(/*anything*/ it){ // summary: // similar to dojo.isArray() but more permissive // description: // Doesn't strongly test for arrayness. Instead, settles for isn't // a string or number and has a length property. Arguments objects // and DOM collections will return true when passed to // dojo.isArrayLike(), but will return false when passed to // dojo.isArray(). // returns: // If it walks like a duck and quacks like a duck, return
Re: array like objects
2009/12/8 Brendan Eich bren...@mozilla.com: On Dec 8, 2009, at 11:51 AM, Erik Corry wrote: for (let i in arraylike) { i |= 0; If this pattern catches on then we could optimize for it without changing the language. Yeah, but some day there will be only new versions in which i is numeric for arraylikes and that becomes pointless. On that fine day programmers can stop writing the ugly extra statement. That's worth something too, even as a new loop construct could be nicer. Do we want nicer with high migration tax and greater total language complexity (new loop construct), or nicer with lower tax (reformed for-in under new opt-in version), or not-so-nice with perpetual type-fixup kludge Well, we have use strict, and then this would give us use integer, so all that leaves would be an excuse to shoehorn use vmsish into the language :) (what you seem resigned to :-P). I think returning integers from for-in is a complete non-starter but I'm not volunteering to build a browser that does it just so I can check what breaks. I'll handle that chore... /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: array like objects
On Dec 8, 2009, at 12:52 PM, Mike Samuel wrote: 2009/12/8 Brendan Eich bren...@mozilla.com: On Dec 8, 2009, at 11:51 AM, Erik Corry wrote: for (let i in arraylike) { i |= 0; If this pattern catches on then we could optimize for it without changing the language. Yeah, but some day there will be only new versions in which i is numeric for arraylikes and that becomes pointless. On that fine day programmers can stop writing the ugly extra statement. That's worth something too, even as a new loop construct could be nicer. Do we want nicer with high migration tax and greater total language complexity (new loop construct), or nicer with lower tax (reformed for-in under new opt-in version), or not-so-nice with perpetual type-fixup kludge Well, we have use strict, and then this would give us use integer, so all that leaves would be an excuse to shoehorn use vmsish into the language :) I remember VMS. Not as good as TOPS-20 :-P. Seriously, opt-in versioning will not be via too many use mumble pragmas, rather whole-edition selection a la RFC 4329. The use strict idea is good but we don't want endless feature knobs (we = everyone, TC39, developers, implementors). More, while in-language version selection may yet happen, I don't see how it helps with new syntax. You'll get syntax errors from old browsers without any way to handle them (no fallback or alt content for script). More controllable (for authors) is something like the sketch here: http://wiki.ecmascript.org/doku.php?id=proposals:versioning linked from http://wiki.ecmascript.org/doku.php?id=strawman:versioning Your thoughts and edits are welcome on this last page. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: array like objects
Your strawman would support: {0: strawman, length: 0} A better definition might be: o is an array like object if o[[Get]]('length') returns a Number one greater than the largest numeric property, or 0 if no numeric properties exist. Yehuda Katz Developer | Engine Yard (ph) 718.877.1325 On Mon, Dec 7, 2009 at 5:33 PM, Mike Samuel mikesam...@gmail.com wrote: It occurred to me after looking at the proxy strawman that it might help to nail down what array-like means in future drafts. It isn't directly related to the proxy stuff though so I thought I'd start a separate thread. I've seen quite a bit of library code that does something like if (isArrayLike(input)) { // iterate over properties [0,length) in increasing order } else { // Iterate over key value pairs } but different libraries defined array-like in different ways. Some ways I've seen: (1) input instanceof Array (2) Object.prototype.toString(input) === '[object Array]' (3) input.length === (input.length 0) etc. The common thread with array like objects is that they are meant to be iterated over in series. It might simplify library code and reduce confusion among clients of these libraries if there is some consistent definition of series-ness. This committee might want to get involved since it could affect discussions on a few topics: (1) key iteration order (2) generators/iterators (3) catchall proposals (4) type systems One strawman definition for an array like object: o is an array like object if o[[Get]]('length') returns a valid array index or one greater than the largest valid array index. The need to distinguish between the two in library code could be mooted if for (in) on arrays iterated over the array index properties of arrays in numeric oder order first, followed by other properties in insertion order, and host objects like NodeCollections followed suit. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
RE: array like objects
Curiously, I don't believe any of the generic functions for arrays and array-like objects in section 15.4.4 actually depend upon such an array-like test. They all simply use ToUint32 applied to the value of the length property. If the length property doesn't exist or its value isn't something that an a convertible representation of a number, the value 0 is used as the length and not much happens. By this definition, all objects are essentially array-like but many have no array-like elements. It make one wonder why if this definition works satisfactory for the built-ins it should be used for all array-like situations. Allen From: es-discuss-boun...@mozilla.org [mailto:es-discuss-boun...@mozilla.org] On Behalf Of Yehuda Katz Sent: Monday, December 07, 2009 5:40 PM To: mikesam...@gmail.com Cc: es-discuss Subject: Re: array like objects Your strawman would support: {0: strawman, length: 0} A better definition might be: o is an array like object if o[[Get]]('length') returns a Number one greater than the largest numeric property, or 0 if no numeric properties exist. Yehuda Katz Developer | Engine Yard (ph) 718.877.1325 On Mon, Dec 7, 2009 at 5:33 PM, Mike Samuel mikesam...@gmail.commailto:mikesam...@gmail.com wrote: It occurred to me after looking at the proxy strawman that it might help to nail down what array-like means in future drafts. It isn't directly related to the proxy stuff though so I thought I'd start a separate thread. I've seen quite a bit of library code that does something like if (isArrayLike(input)) { // iterate over properties [0,length) in increasing order } else { // Iterate over key value pairs } but different libraries defined array-like in different ways. Some ways I've seen: (1) input instanceof Array (2) Object.prototype.toString(input) === '[object Array]' (3) input.length === (input.length 0) etc. The common thread with array like objects is that they are meant to be iterated over in series. It might simplify library code and reduce confusion among clients of these libraries if there is some consistent definition of series-ness. This committee might want to get involved since it could affect discussions on a few topics: (1) key iteration order (2) generators/iterators (3) catchall proposals (4) type systems One strawman definition for an array like object: o is an array like object if o[[Get]]('length') returns a valid array index or one greater than the largest valid array index. The need to distinguish between the two in library code could be mooted if for (in) on arrays iterated over the array index properties of arrays in numeric oder order first, followed by other properties in insertion order, and host objects like NodeCollections followed suit. ___ es-discuss mailing list es-discuss@mozilla.orgmailto:es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: array like objects
2009/12/7 Yehuda Katz wyc...@gmail.com: Your strawman would support: {0: strawman, length: 0} A better definition might be: o is an array like object if o[[Get]]('length') returns a Number one greater than the largest numeric property, or 0 if no numeric properties exist. By that better definition the array [,] is not array like. Yehuda Katz Developer | Engine Yard (ph) 718.877.1325 On Mon, Dec 7, 2009 at 5:33 PM, Mike Samuel mikesam...@gmail.com wrote: It occurred to me after looking at the proxy strawman that it might help to nail down what array-like means in future drafts. It isn't directly related to the proxy stuff though so I thought I'd start a separate thread. I've seen quite a bit of library code that does something like if (isArrayLike(input)) { // iterate over properties [0,length) in increasing order } else { // Iterate over key value pairs } but different libraries defined array-like in different ways. Some ways I've seen: (1) input instanceof Array (2) Object.prototype.toString(input) === '[object Array]' (3) input.length === (input.length 0) etc. The common thread with array like objects is that they are meant to be iterated over in series. It might simplify library code and reduce confusion among clients of these libraries if there is some consistent definition of series-ness. This committee might want to get involved since it could affect discussions on a few topics: (1) key iteration order (2) generators/iterators (3) catchall proposals (4) type systems One strawman definition for an array like object: o is an array like object if o[[Get]]('length') returns a valid array index or one greater than the largest valid array index. The need to distinguish between the two in library code could be mooted if for (in) on arrays iterated over the array index properties of arrays in numeric oder order first, followed by other properties in insertion order, and host objects like NodeCollections followed suit. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: array like objects
The one that I use is function isArrayLike(i){ return (typeof i !==string) i.length !== void (0); } It might not be perfect, but it allows me to make certain assumptions about the input that are useful enough. Keep in mind that an Array may have a length of 5, and all those values are undefined, so {length:4} could be used as a valid arrayLike, and that seems reasonable to me. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: array like objects
On Tue, Dec 8, 2009 at 1:29 PM, Breton Slivka z...@zenpsycho.com wrote: The one that I use is function isArrayLike(i){ return (typeof i !==string) i.length !== void (0); } It might not be perfect, but it allows me to make certain assumptions about the input that are useful enough. Keep in mind that an Array may have a length of 5, and all those values are undefined, so {length:4} could be used as a valid arrayLike, and that seems reasonable to me. On Tue, Dec 8, 2009 at 1:18 PM, Allen Wirfs-Brock allen.wirfs-br...@microsoft.com wrote: Curiously, I don’t believe any of the “generic” functions for arrays and array-like objects in section 15.4.4 actually depend upon such an “array-like” test. They all simply use ToUint32 applied to the value of the length property. If the length property doesn’t exist or its value isn’t something that an a convertible representation of a number, the value 0 is used as the length and not much happens. By this definition, all objects are essentially array-like but many have no array-like elements. You've encapsulated here some of the reasoning behind my earlier test- Anything that passes my test is acceptable to any of the array prototype functions, but filters out two situations that I've found I didn't intend an object to be treated as an array. My usecase is overloaded functions that may also accept objects, and strings, and arraylikes, but I want a way to distinguish array-likes from objects and strings. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: array like objects
2009/12/7 Allen Wirfs-Brock allen.wirfs-br...@microsoft.com: Curiously, I don’t believe any of the “generic” functions for arrays and array-like objects in section 15.4.4 actually depend upon such an “array-like” test. They all simply use ToUint32 applied to the value of the length property. If the length property doesn’t exist or its value isn’t something that an a convertible representation of a number, the value 0 is used as the length and not much happens. By this definition, all objects are essentially array-like but many have no array-like elements. Most of the code snippets I've seen use it to decide how to iterate over elements and whether to produce an array or Object as output, not to decide whether it's appropriate to apply Array generics. The each function from http://code.jquery.com/jquery-latest.js does if ( args ) { if ( length === undefined ) { // iterate using for in } else for ( ; i length; ) And then any library routines that delegate to each to build an output inherit the same definition. I It make one wonder why if this definition works satisfactory for the built-ins it should be used for all array-like situations. Allen From: es-discuss-boun...@mozilla.org [mailto:es-discuss-boun...@mozilla.org] On Behalf Of Yehuda Katz Sent: Monday, December 07, 2009 5:40 PM To: mikesam...@gmail.com Cc: es-discuss Subject: Re: array like objects Your strawman would support: {0: strawman, length: 0} A better definition might be: o is an array like object if o[[Get]]('length') returns a Number one greater than the largest numeric property, or 0 if no numeric properties exist. Yehuda Katz Developer | Engine Yard (ph) 718.877.1325 On Mon, Dec 7, 2009 at 5:33 PM, Mike Samuel mikesam...@gmail.com wrote: It occurred to me after looking at the proxy strawman that it might help to nail down what array-like means in future drafts. It isn't directly related to the proxy stuff though so I thought I'd start a separate thread. I've seen quite a bit of library code that does something like if (isArrayLike(input)) { // iterate over properties [0,length) in increasing order } else { // Iterate over key value pairs } but different libraries defined array-like in different ways. Some ways I've seen: (1) input instanceof Array (2) Object.prototype.toString(input) === '[object Array]' (3) input.length === (input.length 0) etc. The common thread with array like objects is that they are meant to be iterated over in series. It might simplify library code and reduce confusion among clients of these libraries if there is some consistent definition of series-ness. This committee might want to get involved since it could affect discussions on a few topics: (1) key iteration order (2) generators/iterators (3) catchall proposals (4) type systems One strawman definition for an array like object: o is an array like object if o[[Get]]('length') returns a valid array index or one greater than the largest valid array index. The need to distinguish between the two in library code could be mooted if for (in) on arrays iterated over the array index properties of arrays in numeric oder order first, followed by other properties in insertion order, and host objects like NodeCollections followed suit. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: array like objects
2009/12/7 Breton Slivka z...@zenpsycho.com: The one that I use is function isArrayLike(i){ return (typeof i !==string) i.length !== void (0); I like that it's efficient. How about if (i !== null typeof i === 'object') { var len = i.length; var ilen = len 0; return (len === ilen ilen = 0 ilen = 0x8000) } return false; Less efficient, but doesn't fail for null, skips functions which do have a length, and requires length to be a valid array length only performing one get and one toNumber. } It might not be perfect, but it allows me to make certain assumptions about the input that are useful enough. Keep in mind that an Array may have a length of 5, and all those values are undefined, so {length:4} could be used as a valid arrayLike, and that seems reasonable to me. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss