Re: array like objects

2009-12-16 Thread P T Withington
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

2009-12-15 Thread Jorge Chamorro
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

2009-12-15 Thread Brendan Eich


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

2009-12-15 Thread Brendan Eich

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

2009-12-15 Thread Jorge Chamorro
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

2009-12-15 Thread Brendan Eich

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

2009-12-15 Thread David-Sarah Hopwood
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

2009-12-15 Thread Brendan Eich

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

2009-12-15 Thread David-Sarah Hopwood
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-14 Thread Mike Samuel
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

2009-12-14 Thread Garrett Smith
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

2009-12-14 Thread Breton Slivka
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 Thread Mike Samuel
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

2009-12-14 Thread Breton Slivka
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

2009-12-14 Thread Garrett Smith
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

2009-12-13 Thread Brendan Eich

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

2009-12-12 Thread Mike Wilson
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

2009-12-12 Thread Garrett Smith
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

2009-12-12 Thread Mike Wilson
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

2009-12-12 Thread Brendan Eich

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

2009-12-12 Thread Brendan Eich

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

2009-12-12 Thread Garrett Smith
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

2009-12-12 Thread Mark S. Miller
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

2009-12-12 Thread Mark S. Miller
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

2009-12-12 Thread Mark S. Miller
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 Thread Mike Samuel
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 Thread Mike Samuel
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

2009-12-12 Thread Garrett Smith
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

2009-12-11 Thread Mike Wilson
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

2009-12-11 Thread Mark S. Miller
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

2009-12-11 Thread Mark S. Miller
[+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

2009-12-11 Thread David-Sarah Hopwood
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-08 Thread Erik Corry
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-08 Thread Mike Samuel
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

2009-12-08 Thread Juriy Zaytsev

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

2009-12-08 Thread Brendan Eich

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-08 Thread Mike Samuel
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-08 Thread Mike Samuel
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

2009-12-08 Thread Brendan Eich

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

2009-12-07 Thread Yehuda Katz
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-07 Thread Allen Wirfs-Brock
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-07 Thread Mike Samuel
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

2009-12-07 Thread Breton Slivka
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

2009-12-07 Thread Breton Slivka
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-07 Thread Mike Samuel
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-07 Thread Mike Samuel
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