Description
TypedArray, %TypedArray%.from, and Array.from have a lot of redundancy between their iterator vs. array-like consumption branches, but they are also unnecessarily divergent from each other.
API | iterator input | array-like input |
---|---|---|
new TypedArray(input) |
|
|
%TypedArray%.from(input) |
|
|
Array.from(input) |
|
|
The two TypedArray APIs are very similar to each other, and the difference between branches inside of each is basically that iterator input is "fully" consumed up front to determine a length for allocation before entering a ? Set loop while non-iterator input is used to allocate with length LengthOfArrayLike before entering a ? Get + ? Set loop (i.e., the former performs all [fallible] reads before any [fallible] write, while the latter performs element reads and writes in [fallible] pairs before advancing). It would be nice to impose a threshold on the former (presumably implementation-defined but normatively capped at 2**53 - 1, corresponding with the eventual constraints of AllocateTypedArrayBuffer anyway), which (if desired) could also be used to consolidate the branches into something like
- If usingIterator is not undefined, then
- Let limit be TypedArraySizeLimit(C).
- Let arrayLike be ? IteratorToArrayLike(? GetIteratorFromMethod(source, usingIterator), limit).
- Else,
- NOTE: source is not an iterable object, so assume it is already an array-like object.
- Let arrayLike be ? ToObject(source).
- NOTE: When usingIterator is not undefined, arrayLike is not observable from ECMAScript code and each of the following calls upon it will neither call user code nor return an abrupt completion.
- Let len be ? LengthOfArrayLike(arrayLike).
- Let O be ? TypedArrayCreateFromConstructor(C, « 𝔽(len) »).
- Let k be 0.
- Repeat, while k < len,
- Let Pk be ! ToString(𝔽(k)).
- Let kValue be ? Get(arrayLike, Pk).
- If mapping is true, then
- Let mappedValue be ? Call(mapper, thisArg, « kValue, 𝔽(k) »).
- Else,
- Let mappedValue be kValue.
- Perform ? Set(O, Pk, mappedValue, true).
- Set k to k + 1.
Array.from could be left alone, or (because the iterator branch already operates by read/write pairs) similarly consolidated via use of a non-observable iterator. I prefer leaving it for now, but at any rate not applying normative changes (unless we actually want to support the currently non-conformant behavior that never reaches 2**53 - 1).