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

David Bruant bruant.d at gmail.com
Tue Nov 1 14:17:20 PDT 2011


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 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 at mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss



More information about the es-discuss mailing list