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: Catch-all proposal based on proxies
2009/12/11 Mark S. Miller erig...@google.com: On Fri, Dec 11, 2009 at 9:31 AM, Brendan Eich bren...@mozilla.com wrote: On Dec 11, 2009, at 8:36 AM, Maciej Stachowiak wrote: On Dec 10, 2009, at 10:06 PM, Mark S. Miller wrote: has 263. I will proceed to worry only about hasOwnProperty until someone objects. Note that these are hits found in source repositories, not on the Web. So I would not put too much stock in the number of hits except as an existence proof. Both of these include hits from JavaScript libraries, likely meaning there are many deployed copies of the code in question (though unclear if that code path gets hit as the JS libraries are used in practice). Absolutely. The best case with codesearch would be to get no results -- that would suggest but not prove that the construct is not used. Getting any hits casts doubt on claim that the construct isn't used enough to worry about. More than a few handfuls of hits - you should worry. Mark, I don't think we can pick meta-level methods to worry about and not worry about, if the goal is transparent wrapping or catch-all based DOM emulations. OTOH, propertyIsEnumerable is much less used than hasOwnProperty, whether directly or via .call. But in principle it is the same kind of animal. I have now changed the spec so that Object.prototype.hasOwnProperty.call and Object.prototype. propertyIsEnumerable.call are base level rather than meta level methods. Proxies can now virtualize them fine, at the price of loading down the handler protocol with two more methods. As discussed earlier, I also added an invoke: trap so that named method invocations can be handled in one step without having to curry over the method name. So, altogether, three more methods. On the other hand, the double reflection needed by the membrane became simpler and faster, since the choke point is now an invoke trap. Of legacy methods, the only one which is still meta-level is Object.prototype.toString.call, as is necessary to preserve its meaning. The similar Function.prototype.toString.call remains in limbo awaiting a clearer spec. Neither of these should impede faithful emulation of existing DOM expectations. On the interaction of Function.prototype.toString and function proxies, one use case is code that tries to get at a function's name as by doing function nameOf(f) { if ('name' in f) { return f.name; } // Works on some interpreters var m = ('' + f).match(/^function\s+([^(\s]+)/); return m ? m[1] : void 0; } I'm not sure how much of the existing code like this invokes toString directly or indirectly instead of using Function.prototype.toString. Function proxy handlers could implement has('name') then there might not be a need for Function.prototype.toString to support this use case. -- Cheers, --MarkM ___ 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 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
[[HasOwnProperty]]
[[HasOwnProperty]] is mentioned in one place in the spec: s 15.4.4.11 Array.prototype.sort (comparefn). There is no mention of [[HasOwnProperty]] anywhere else. I also see a [[GetOwnProperty]] definition in Table 8 and a definition for own property (s. 4.3.30). Is there a difference between [[HasOwnProperty]] and own property? If not, then one or the other should be used. If so, then [[HasOwnProperty]] should be defined somewhere in the spec. 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: [[HasOwnProperty]]
[+es5-discuss] Thanks for reporting. But please include es5-discuss on all messages pointing out mistakes in the ES5 spec. It will help us accumulate errata. On Sat, Dec 12, 2009 at 11:29 AM, Garrett Smith dhtmlkitc...@gmail.comwrote: [[HasOwnProperty]] is mentioned in one place in the spec: s 15.4.4.11 Array.prototype.sort (comparefn). There is no mention of [[HasOwnProperty]] anywhere else. I also see a [[GetOwnProperty]] definition in Table 8 and a definition for own property (s. 4.3.30). Is there a difference between [[HasOwnProperty]] and own property? If not, then one or the other should be used. If so, then [[HasOwnProperty]] should be defined somewhere in the spec. 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
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: Catch-all proposal based on proxies
On Dec 12, 2009, at 11:08 AM, Mark S. Miller wrote: On Sat, Dec 12, 2009 at 10:53 AM, Mike Samuel mikesam...@gmail.com wrote: On the interaction of Function.prototype.toString and function proxies, one use case is code that tries to get at a function's name as by doing function nameOf(f) { if ('name' in f) { return f.name; } // Works on some interpreters var m = ('' + f).match(/^function\s+([^(\s]+)/); return m ? m[1] : void 0; } I'm not sure how much of the existing code like this invokes toString directly or indirectly instead of using Function.prototype.toString. Function proxy handlers could implement has('name') then there might not be a need for Function.prototype.toString to support this use case. Under the current proposal, a trapping function proxy f can virtualize all the following without problem: 'name' in f f.name '' + f f.toString() The only open issue is Function.prototype.toString.call(f) I would have ventured a guess that this isn't used in real code. But having learned my lesson ;), I looked. What do we all think of http://www.google.com/codesearch?hl=enlr=q=Function.prototype.toString.call+lang:javascriptsbtn=Search ? Interesting. A few of these uses appear to be in JavaScript libraries so they could be widespread. I see a few different uses: - To get the function name - To detect if something is a function at all (by seeing if the attempt to call it throws) - To check for function equality (likely a bogus check!) - To get argument names - Something else mysterious that I couldn't figure out (looking for calls to the Function constructor inside the function body?) Note though that in the case of DOM emulation specifically, probably most of these are not relevant. Looking at toString() on DOM methods is usually done for one of the following reasons: 1) To get the function name. 2) To check for [native code] to verify that a native method hasn't been replaced by JavaScript code (seems like a fairly bogus check). Regards, Maciej ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Weak references and destructors
On Fri, Dec 11, 2009 at 12:45 AM, Erik Corry erik.co...@gmail.com wrote: 2009/12/11 Mark S. Miller erig...@google.com: [...] However, I agree that these proposals should be decoupled if possible. Accordingly, I have kludged [...] I really dislike this definition. This would imply that anyone could overwrite setTimeout and get a completely different behaviour. If overwriting is impossible then it introduces setTimeout into the standard by the backdoor. I'd prefer an underspecified [[QueueForProcessing]] operation with no connection to the global object and a note to say that in a browser it would be expected to use the same mechanism as a setTimeout with a timeout of zero. I agree. Done. To be consistent with the spec style on the rest of that page -- perhaps a bad idea -- I called your [[QueueForProcessing]] operation POSTPONE. This is a minor issue and I'm not attached to the choice. In any case, the most relevant new text is at http://wiki.ecmascript.org/doku.php?id=strawman:weak_references#safe_post_mortem_notification. Thanks for the suggestion. There are lots of misunderstandings around GC, where people expect this sort of callback to happen at some predictable time. If there's no memory pressure then there's no reason to expect the GC to ever be run even if the program runs for ever. It would be nice to have some indication in the text of the standard that discouraged people from expecting a callback at some predictable time. For example if people want to close file descriptors or collect other resources that are not memory using this mechanism it would be nice to discourage them (because it won't work on a machine with lots of memory and not so many max open fds). Does the current text clarify this to your satisfaction? -- Cheers, --MarkM ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: [[HasOwnProperty]]
Garrett Smith wrote: [[HasOwnProperty]] is mentioned in one place in the spec: s 15.4.4.11 Array.prototype.sort (comparefn). There is no mention of [[HasOwnProperty]] anywhere else. I also see a [[GetOwnProperty]] definition in Table 8 and a definition for own property (s. 4.3.30). Is there a difference between [[HasOwnProperty]] and own property? If not, then one or the other should be used. If so, then [[HasOwnProperty]] should be defined somewhere in the spec. Array.prototype.sort should have been defined in terms of [[GetOwnProperty]]. That is, the text in 15.4.4.11 should be # • The result of calling the [[GetOwnProperty]] internal method of # proto with argument ToString(j) is not *undefined*. (Incidentally, I don't see any errata for the published standard at http://wiki.ecmascript.org/doku.php?id=es3.1:es3.1_proposal_working_draft.) -- 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 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: Weak references and destructors
On 2009-12-11, at 12:43, Brendan Eich wrote: It would be more than nice. It is important that the spec not mandate any particular schedule. We have seen endless over-coupling to GC implementation details where programmers who can hook into finalization or another GC phase do so for all the wrong reasons: to close fds, free database cursors, send a message, update UI, etc. Crazy stuff. +n In my experience, it is always a bad idea for the GC to invoke user-code. Please don't throw out the weak-key tables with the finalization bathwater. But if there is no guarantee of when the notification might happen, then programmers should not expect any scheduling akin to setTimeout with a timeout of zero. I initially mis-read this as saying setTimeout with a timeout of 0 might never be scheduled. But that's not what you said. -- I was amused by this aside from the strawman: Since I can never remember the black/white polarity of traditional gc descriptions, I will use retained for black, fringe for gray, and untraced for white. ___ 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: Catch-all proposal based on proxies
2009/12/12 Mark S. Miller erig...@google.com: On Sat, Dec 12, 2009 at 10:53 AM, Mike Samuel mikesam...@gmail.com wrote: On the interaction of Function.prototype.toString and function proxies, one use case is code that tries to get at a function's name as by doing function nameOf(f) { if ('name' in f) { return f.name; } // Works on some interpreters var m = ('' + f).match(/^function\s+([^(\s]+)/); return m ? m[1] : void 0; } I'm not sure how much of the existing code like this invokes toString directly or indirectly instead of using Function.prototype.toString. Function proxy handlers could implement has('name') then there might not be a need for Function.prototype.toString to support this use case. Under the current proposal, a trapping function proxy f can virtualize all the following without problem: 'name' in f f.name '' + f f.toString() The only open issue is Function.prototype.toString.call(f) I would have ventured a guess that this isn't used in real code. But having learned my lesson ;), I looked. What do we all think of http://www.google.com/codesearch?hl=enlr=q=Function.prototype.toString.call+lang:javascriptsbtn=Search? So in your search results, prototype is extracting formal parameter names. argumentNames: function() { var names = Function.prototype.toString.call(this) .match(/^[\s\(]*function[^(]*\(([^\)]*)\)/)[1] .replace(/\s+/g, '').split(','); return names.length == 1 !names[0] ? [] : names; }, -- 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