Re: Wanted: standard Array function to append an array's elements to another array

2011-11-01 Thread David Bruant
Hi,

I have just noticed [1], read all messages on this thread and thought
that the JavaScript stack size limit for
Array.prototype.push.apply(firstArray, secondArray); was an
implementation concern rather than anything else and it really sounds
weird to me to add a method just because implementations aren't capable
of performing well with some methods.
Theorically speaking, why .pushAll would do better than
.push.apply+second argument? There is no reason I can think of.

I think that implementors did implement strictly ES5 definition of push:
Array.prototype.push ( [ item1 [ , item2 [ , … ] ] ] ) which considers
each item as a new argument, making the stack grow. Why would a .pushAll
do better? Because there is only one argument which is an array. So I
think that instead of adding pushAll, we'd rather redefine .push with
the great ...rest parameters [2]

Array.prototype.push = function(...items){
let O = ToObject(this);
let lenVal = O.length;
let n = ToUint32(lenVal);
let itemsList = ToList(items); // sorry for the bickshed
while(itemsList.length != 0){
let E = itemsList.pop(); // bickshed bis
O[n] = E;
n++;
O.length = n;
}
return n;
};

(which is pretty much Jeff's implementation of .pushAll in the initial
message)

As a matter of fact, maybe that all methods that where previously
defined as myFunction(a, b [, c1 [, c2 [ , … ] ] ]) would have rather
being re-specified in the form of myFunction(a, b, ...c). Should I
file a bug on that?

Regarding implementations of .push, if they can do as good as a .pushAll
could, then they are just buggy and should be fixed in my opinion.

What do you think?

David

[1] http://wiki.ecmascript.org/doku.php?id=strawman:array.prototype.pushall
[2] http://wiki.ecmascript.org/doku.php?id=harmony:rest_parameters


Le 25/07/2011 21:54, Jeff Walden a écrit :
 If I have one array, and I want to append the contents of an arbitrary
 array to it, and I don't need the unmodified first array after
 appending the second array's elements to it, I have three options.

 First, I can use Array.prototype.concat to create a new array
 consisting of the first array, then the contents of the second. But
 this creates a new array rather than mutating the first array, so it
 potentially wastes memory proportional to the size of the first array,
 barring complicated heuristics to recognize and avoid the waste.
 Potentially worse, if any element of the second array is an Array,
 instead of that array being appended, its elements will be appended.

 Second, I can use Array.prototype.push:

 Array.prototype.push.apply(firstArray, secondArray);

 This avoids the memory-wastefulness concern, and it doesn't treat
 Array items specially. But it introduces a third concern: the
 JavaScript stack size limit, if the second array contains a
 particularly large number of elements. This might manifest itself as
 causing a stack overflow exception, or it might cause only some of the
 elements of the second array to be appended (an arguably buggy
 mitigation mechanism, but one some engines use, at least currently).

 Third, I can use Array.prototype.splice, passing in |start = length|
 and |deleteCount = 0|. But splice too encounters the stack size limit
 problem. Worse, because its arguments are (start, deleteCount,
 newElt1, newElt2, ...), constructing the array of arguments with which
 to apply the splice method seems to require complicated copy-on-write
 array-element-sharing to mutate the first array without consuming
 twice the first array's memory, or some other tricky scheme. For such
 schemes to be effective here, the programmer would have to structure
 his code pretty carefully, being sure to only use
 Array.prototype.unshift, say, to implement it. And there's a
 bootstrapping problem to creating the array of arguments to supply to
 splice in order to append the elements of an array to the first array.

 I see no problem-free way to append an array's elements to another
 array without doing it manually. That's not hard, but it's
 error-prone, and it's much trickier to recognize and correctly
 optimize. I think there should be a way to append elements of an
 arbitrarily sized array to another array, mutating that array
 in-place, without consuming excess memory. I'm not too concerned about
 its precise semantics or about what it's named. For a starting point
 I'll propose Array.prototype.pushAll (or extend, following Python, but
 again, I don't really care about the exact name right now):

 Object.defineProperty(Array.prototype, pushAll,
 {
 enumerable: false, configurable: true, writable: true,
 value: function pushAll(other)
 {
 use strict;
 var t = ToObject(this);
 var length = ToUint32(t.length);
 var otherLen = other.length;
 for (var i = 0, j = length; i  otherLen; i++, j++)
 t[j] = other[i];
 t.length = j;
 return void 0;
 },
 });

 Comments? Suggestions? Requests for changes?

 I also had the thought that it might be nice to be able to push a
 subrange of the elements of an array. You could do 

Re: Wanted: standard Array function to append an array's elements to another array

2011-11-01 Thread David Bruant
Le 01/11/2011 22:17, David Bruant a écrit :
 (...)

 Regarding implementations of .push, if they can
I meant *can't*, of course.
 do as good as a .pushAll
 could, then they are just buggy and should be fixed in my opinion.

___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Wanted: standard Array function to append an array's elements to another array

2011-08-01 Thread Jeff Walden

On 07/31/2011 03:57 AM, Andrea Giammarchi wrote:

I agree mine is more a workaround while we need a solution but it's not about Array here, 
it's about number of arguments limit per function so once we have pushAll in place, all 
other methods will still suffer the apply problem


True.  It seems to me the fundamental problem is exposing n-ary functionality 
solely through a variadic interface, and not through an interface accepting an 
array.  Such interfaces are moderately handy for quick hacking.  Yet since 
they're not much handier than adding [] around the variadic arguments, I don't 
see that they provide much value.  Which still leaves the problem of the 
existing variadic methods, of course...

Jeff
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Wanted: standard Array function to append an array's elements to another array

2011-07-31 Thread Andrea Giammarchi
I agree mine is more a workaround while we need a solution but it's not
about Array here, it's about number of arguments limit per function so once
we have pushAll in place, all other methods will still suffer the apply
problem and it's not about apply either, e.g.

var tooMany = Array(0x).join(,$).replace(
/,\$/g,
function (m,i) {return m + i}
).slice(1);

alert(Function(
tooMany,
return [ + tooMany + ].length
)());

Too many parameters in function definition (only 32766 allowed)

So ... this is bad


On Sat, Jul 30, 2011 at 12:10 AM, Jeff Walden jwalden...@mit.edu wrote:

 On 07/29/2011 05:22 AM, Andrea Giammarchi wrote:

 to avoid apply limits is actually trivial


 More or less, yes.

 But it requires the developer to anticipate the concern in advance that the
 elements being appended might consume all available stack space.  I don't
 think most developers think at all about the size of the stack, or about its
 being limited, except when they write a recursive algorithm, intentionally
 or inadvertently, and neglect to correctly implement the base case.  I
 certainly forgot about this concern when I wrote the buggy code which
 initially triggered this request, and I think it's reasonably apparent
 there's a problem when even a JS engine implementer makes this mistake.

 Past that, your MAX_LENGTH constant would have to be lower than the max
 length across all JS engines cared about.  I find it concerning that
 something as simple as extending an array with the elements of another array
 would require an implementation-dependent workaround, when this operation is
 built-in functionality in other mainstream languages where mutation is
 common:

 C++: vectorT::insert
 http://www.cplusplus.com/**reference/stl/vector/insert/http://www.cplusplus.com/reference/stl/vector/insert/

 C#: ListT.AddRange
 http://msdn.microsoft.com/en-**us/library/z883w3dc.aspx#Y570http://msdn.microsoft.com/en-us/library/z883w3dc.aspx#Y570

 Java: ListE.addAll
 http://download.oracle.com/**javase/1.5.0/docs/api/java/**util/List.htmlhttp://download.oracle.com/javase/1.5.0/docs/api/java/util/List.html

 Perl: push
 http://perlmeme.org/howtos/**perlfunc/push_function.htmlhttp://perlmeme.org/howtos/perlfunc/push_function.html

 Python: list.extend
 http://docs.python.org/**tutorial/datastructures.htmlhttp://docs.python.org/tutorial/datastructures.html

 Ruby: array.concat
 http://www.ruby-doc.org/core/**classes/Array.html#M000224http://www.ruby-doc.org/core/classes/Array.html#M000224

 Jeff

___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Wanted: standard Array function to append an array's

2011-07-29 Thread Andrea Giammarchi
I may be late here, but what's wrong with

firstArray = firstArray.concat(secondArray); ?

If there are still problems I would say no magic method can solve them,
isn't it?


On Fri, Jul 29, 2011 at 1:59 AM, Jeff Walden jwalden...@mit.edu wrote:

 On 07/27/2011 01:26 PM, John-David Dalton wrote:

 @Jeff In reply to
 https://mail.mozilla.org/**pipermail/es-discuss/2011-**July/016124.htmlhttps://mail.mozilla.org/pipermail/es-discuss/2011-July/016124.html
 ,
 which engines have problems with `firstArray.push.apply(**firstArray,
 secondArray)` ?
 Shouldn't a bug report be filed for the specific JS engine or the spec
 be clarified on the subject (String.fromCharCode too) instead of
 adding another method to Array.prototype?


 Here's a testcase:

 (function test() { var big =  [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc,
 0xd, 0xe, 0xf]; while (true) { try { var before = big.length;
 big.push.apply(big, big); if (big.length !== before + before) throw before;
 } catch (e) { return big.length + :  + e; } } })()

 If the apply call throws an exception, a string consisting of the array
 length before the push failed, and the exception thrown, is returned.  If
 the push call doesn't push all the elements it should have pushed,a string
 consisting of the array length after the push, and the array length before
 the faulty push, is returned.

 The testcase demonstrates failures with these engines:

 SpiderMonkey's max argument-count is currently something like 480k, so
 pushing an array of 512k elements onto another array will only push the
 first 480k-ish.  (This is being changed so that an exception is thrown,
 shortly.  It has caused at least two quite unexpected bugs.  Probably
 someone else has stumbled across the problem before, but I don't know for
 sure.)

 In v8 an exception is thrown sometime between secondArray having length
 128k and 256k.

 Nitro copied SpiderMonkey, although its max-arg-count isn't as high as
 SpiderMonkey's, so it will only push the first N elements of a really big
 array.

 IE10 throws an exception for a push of the elements of an array somewhere
 between 128k and 256k.

 IE9 throws similarly, except between 256k and 512k.

 Of the major engines, only Opera seems to have no problems here.  I'm not
 sure why this is.  But ignoring Opera, everyone fails this.  And the reason,
 I believe, is not that it's a quality of implementation issue: it's that the
 general way to implement this butts up against ingrained implementation
 choices, and different engines will quite rationally behave in different
 ways in response.  push.apply is simply not a reliable substitute for a
 built-in method to push the contents of an array into another array.

 Jeff

 __**_
 es-discuss mailing list
 es-discuss@mozilla.org
 https://mail.mozilla.org/**listinfo/es-discusshttps://mail.mozilla.org/listinfo/es-discuss

___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Wanted: standard Array function to append an array's elements to another array

2011-07-29 Thread Andrea Giammarchi
to avoid apply limits is actually trivial:

var fromCharCode = (function ($fromCharCode, MAX_LENGTH) {
return function fromCharCode(code) {
typeof code == number  (code = [code]);
for (var
result = [],
i = 0,
length = code.length;
i  length; i += MAX_LENGTH
) {
result.push($fromCharCode.apply(null, code.slice(i, i +
MAX_LENGTH)));
}
return result.join();
};
}(String.fromCharCode, 2048));

// example
alert(fromCharCode(80)); // P
alert(fromCharCode([80,81,82,83,84])); // PQRST

about the pushAll I wonder if concat does not do already exactly what you
are looking for, as I wrote in the other thread.

Best Regards,
Andrea Giammarchi

On Mon, Jul 25, 2011 at 10:17 PM, Jeff Walden jwalden...@mit.edu wrote:

 It's perhaps worth noting that this problem also occurs with
 String.fromCharCode.  I suspect the need for a version of
 |String.fromCharCode.apply(**null, codesArray)| that always works, even
 for super-big |codesArray|, is rather smaller than for the similar
 Array.prototype.push concern.


 Jeff
 __**_
 es-discuss mailing list
 es-discuss@mozilla.org
 https://mail.mozilla.org/**listinfo/es-discusshttps://mail.mozilla.org/listinfo/es-discuss

___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Wanted: standard Array function to append an array's

2011-07-29 Thread Jeff Walden

On 07/29/2011 05:01 AM, Andrea Giammarchi wrote:

I may be late here, but what's wrong with

firstArray = firstArray.concat(secondArray); ?

If there are still problems I would say no magic method can solve them, isn't 
it?


That creates a new array rather than mutate the array originally referred to by 
|firstArray| here, and I originally specified that only mutation was 
acceptable, because creating a new array requires extra space proportional to 
the length of |firstArray|.

But I assume you're arguing that an engine could recognize that the copy could 
be transformed into a mutation.  You'd have to prove that was the *only* 
reference to the original array in order to perform that optimization, or prove 
that it was observably correct to do that.   Such analysis is tricky and costly 
time-wise.  Relying on it would also be performance-fragile.  If you were 
pushing incrementally onto an array (say, because you were appending arrays of 
bytes read from a network stream, saving them up to be processed all at once), 
the entire process is O(n) in bytes processed with push-through-mutation.  But 
it's O(n**2) with push-by-copying.  Thus you'd have to require the developer to 
understand when the optimization could be applied, in order to structure his 
code such that it would be applied.  That level of understanding of compilers, 
and of the algorithms actually used to implement them (which won't be publicly 
available for some engines), seems way way beyond wh
at can reasonably be expected of web developers.

Jeff
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Wanted: standard Array function to append an array's elements to another array

2011-07-29 Thread Jeff Walden

On 07/29/2011 05:22 AM, Andrea Giammarchi wrote:

to avoid apply limits is actually trivial


More or less, yes.

But it requires the developer to anticipate the concern in advance that the 
elements being appended might consume all available stack space.  I don't think 
most developers think at all about the size of the stack, or about its being 
limited, except when they write a recursive algorithm, intentionally or 
inadvertently, and neglect to correctly implement the base case.  I certainly 
forgot about this concern when I wrote the buggy code which initially triggered 
this request, and I think it's reasonably apparent there's a problem when even 
a JS engine implementer makes this mistake.

Past that, your MAX_LENGTH constant would have to be lower than the max length 
across all JS engines cared about.  I find it concerning that something as 
simple as extending an array with the elements of another array would require 
an implementation-dependent workaround, when this operation is built-in 
functionality in other mainstream languages where mutation is common:

C++: vectorT::insert
http://www.cplusplus.com/reference/stl/vector/insert/

C#: ListT.AddRange
http://msdn.microsoft.com/en-us/library/z883w3dc.aspx#Y570

Java: ListE.addAll
http://download.oracle.com/javase/1.5.0/docs/api/java/util/List.html

Perl: push
http://perlmeme.org/howtos/perlfunc/push_function.html

Python: list.extend
http://docs.python.org/tutorial/datastructures.html

Ruby: array.concat
http://www.ruby-doc.org/core/classes/Array.html#M000224

Jeff
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Wanted: standard Array function to append an array's elements to another array

2011-07-28 Thread Jeff Walden

On 07/27/2011 10:12 PM, Mark S. Miller wrote:

We could debate the pros and cons of this sort of chaining convention in 
general. However, in this case I think the more important issue is API 
consistency.


I was thinking this might actually be more consistent, to return this.  
Consider Array.prototype.sort, for example.  (Or maybe the new length would be 
more consistent with Array.prototype.push, on second thought.)

It does seem a reasonable guideline to return something when something can be 
returned, and not to return nothing.  Returning |undefined| was just my not 
having thought of an obviously meaningful and plausible value to return.  But 
I'm fine with any of these return values -- the pushing-the-array-contents 
business is the only truly important part of the method to me.

Jeff
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Wanted: standard Array function to append an array's

2011-07-28 Thread Jeff Walden

On 07/27/2011 01:26 PM, John-David Dalton wrote:

@Jeff In reply to
https://mail.mozilla.org/pipermail/es-discuss/2011-July/016124.html,
which engines have problems with `firstArray.push.apply(firstArray,
secondArray)` ?
Shouldn't a bug report be filed for the specific JS engine or the spec
be clarified on the subject (String.fromCharCode too) instead of
adding another method to Array.prototype?


Here's a testcase:

(function test() { var big =  [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 
0xf]; while (true) { try { var before = big.length; big.push.apply(big, big); if 
(big.length !== before + before) throw before; } catch (e) { return big.length + : 
 + e; } } })()

If the apply call throws an exception, a string consisting of the array length 
before the push failed, and the exception thrown, is returned.  If the push 
call doesn't push all the elements it should have pushed,a string consisting of 
the array length after the push, and the array length before the faulty push, 
is returned.

The testcase demonstrates failures with these engines:

SpiderMonkey's max argument-count is currently something like 480k, so pushing 
an array of 512k elements onto another array will only push the first 480k-ish. 
 (This is being changed so that an exception is thrown, shortly.  It has caused 
at least two quite unexpected bugs.  Probably someone else has stumbled across 
the problem before, but I don't know for sure.)

In v8 an exception is thrown sometime between secondArray having length 128k 
and 256k.

Nitro copied SpiderMonkey, although its max-arg-count isn't as high as 
SpiderMonkey's, so it will only push the first N elements of a really big array.

IE10 throws an exception for a push of the elements of an array somewhere 
between 128k and 256k.

IE9 throws similarly, except between 256k and 512k.

Of the major engines, only Opera seems to have no problems here.  I'm not sure 
why this is.  But ignoring Opera, everyone fails this.  And the reason, I 
believe, is not that it's a quality of implementation issue: it's that the 
general way to implement this butts up against ingrained implementation 
choices, and different engines will quite rationally behave in different ways 
in response.  push.apply is simply not a reliable substitute for a built-in 
method to push the contents of an array into another array.

Jeff
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Wanted: standard Array function to append an array's elements to another array

2011-07-27 Thread David Flanagan

On 7/25/11 12:54 PM, Jeff Walden wrote:

  Object.defineProperty(Array.prototype, pushAll,
  {
enumerable: false, configurable: true, writable: true,
value: function pushAll(other)
{
  use strict;
  var t = ToObject(this);
  var length = ToUint32(t.length);
  var otherLen = other.length;
  for (var i = 0, j = length; i  otherLen; i++, j++)
t[j] = other[i];
  t.length = j;
  return void 0;
},
  });

Comments?  Suggestions?  Requests for changes? 
Could you return this instead of undefined so that we can chain calls? 
For example:


   a.pushAll(b).pushAll(c).sort()
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


RE: Wanted: standard Array function to append an array's

2011-07-27 Thread John-David Dalton
@Jeff In reply to
https://mail.mozilla.org/pipermail/es-discuss/2011-July/016124.html,
which engines have problems with `firstArray.push.apply(firstArray,
secondArray)` ?
Shouldn't a bug report be filed for the specific JS engine or the spec
be clarified on the subject (String.fromCharCode too) instead of
adding another method to Array.prototype?

-JDD
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Wanted: standard Array function to append an array's elements to another array

2011-07-27 Thread Mark S. Miller
On Wed, Jul 27, 2011 at 9:21 AM, David Flanagan dflana...@mozilla.comwrote:

 Could you return this instead of undefined so that we can chain calls? For
 example:

   a.pushAll(b).pushAll(c).sort()


We could debate the pros and cons of this sort of chaining convention in
general. However, in this case I think the more important issue is API
consistency. The JS built ins are not defined in this style. It would make
the API much less regular and predictable to have some use this chaining
convention while others -- especially similar others like push -- don't.

I think this applies whether pushAll were actually added to EcmaScript or if
it were added as part of a library that makes it appear as if it is an
additional built-in.

-- 
Cheers,
--MarkM
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Wanted: standard Array function to append an array's elements to another array

2011-07-25 Thread Jeff Walden

If I have one array, and I want to append the contents of an arbitrary array to 
it, and I don't need the unmodified first array after appending the second 
array's elements to it, I have three options.

First, I can use Array.prototype.concat to create a new array consisting of the 
first array, then the contents of the second.  But this creates a new array 
rather than mutating the first array, so it potentially wastes memory 
proportional to the size of the first array, barring complicated heuristics to 
recognize and avoid the waste.  Potentially worse, if any element of the second 
array is an Array, instead of that array being appended, its elements will be 
appended.

Second, I can use Array.prototype.push:

  Array.prototype.push.apply(firstArray, secondArray);

This avoids the memory-wastefulness concern, and it doesn't treat Array items 
specially.  But it introduces a third concern: the JavaScript stack size limit, 
if the second array contains a particularly large number of elements.  This 
might manifest itself as causing a stack overflow exception, or it might cause 
only some of the elements of the second array to be appended (an arguably buggy 
mitigation mechanism, but one some engines use, at least currently).

Third, I can use Array.prototype.splice, passing in |start = length| and 
|deleteCount = 0|.  But splice too encounters the stack size limit problem.  
Worse, because its arguments are (start, deleteCount, newElt1, newElt2, ...), 
constructing the array of arguments with which to apply the splice method seems 
to require complicated copy-on-write array-element-sharing to mutate the first 
array without consuming twice the first array's memory, or some other tricky 
scheme.  For such schemes to be effective here, the programmer would have to 
structure his code pretty carefully, being sure to only use 
Array.prototype.unshift, say, to implement it.  And there's a bootstrapping 
problem to creating the array of arguments to supply to splice in order to 
append the elements of an array to the first array.

I see no problem-free way to append an array's elements to another array 
without doing it manually.  That's not hard, but it's error-prone, and it's 
much trickier to recognize and correctly optimize.  I think there should be a 
way to append elements of an arbitrarily sized array to another array, mutating 
that array in-place, without consuming excess memory.  I'm not too concerned 
about its precise semantics or about what it's named.  For a starting point 
I'll propose Array.prototype.pushAll (or extend, following Python, but again, I 
don't really care about the exact name right now):

  Object.defineProperty(Array.prototype, pushAll,
  {
enumerable: false, configurable: true, writable: true,
value: function pushAll(other)
{
  use strict;
  var t = ToObject(this);
  var length = ToUint32(t.length);
  var otherLen = other.length;
  for (var i = 0, j = length; i  otherLen; i++, j++)
t[j] = other[i];
  t.length = j;
  return void 0;
},
  });

Comments?  Suggestions?  Requests for changes?

I also had the thought that it might be nice to be able to push a subrange of 
the elements of an array.  You could do that by adding optional |start, length| 
or |start, end| arguments to the method, with corresponding implementation 
changes.  I'm not sure whether this would be useful enough to warrant the 
complexity, but it would be easy to add if people thought it made sense.

Jeff
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Wanted: standard Array function to append an array's elements to another array

2011-07-25 Thread Jeff Walden

It's perhaps worth noting that this problem also occurs with 
String.fromCharCode.  I suspect the need for a version of 
|String.fromCharCode.apply(null, codesArray)| that always works, even for 
super-big |codesArray|, is rather smaller than for the similar 
Array.prototype.push concern.

Jeff
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss