Array subclassing, .map and iterables (Re: Jan 30 TC39 Meeting Notes)

Herby Vojčík herby at mailbox.sk
Sun Feb 10 03:40:25 PST 2013



Allen Wirfs-Brock wrote:
> On Feb 9, 2013, at 3:01 PM, Herby Vojčík wrote:
>
>> Allen Wirfs-Brock wrote:
>>> ethods.
>>>
>>> The choice we agreed to, at the meeting is
>>>
>>> 1) Array.prototype.map produces the same kind of array that it
>>> was applied to, so:
>>>
>>> for the above example m instance of V will be true.
>>> intArray.map(v=>v.toSring()) produces an Int32Array.  The
>>> strings produced by the map function get converted back to
>>> numbers.
>>>
>>> 2) If you want to map the elements of an array to different kind
>>> of array use<ArrayClass>.from with  a map function as the second
>>> parameter:
>>>
>>> var strArray = Array.from(intArray, v=>v.toString());
>>>
>>> This seemed like a less invasive change then adding additional
>>> target kind parameters to Array.prototype.map.  Also it seems
>>> like a very clear way for programmers to state their intent.
>> You chose one default, but I think it was not the simplest one. It
>> is good to see that map is often transforming types, so "the same
>> type" may not be the best default (filter is another story).
>>
>> I think the best would be (it is dead simple): - to _always_ use
>> Array in map result
>
> In your previous post you said:
>
>> 1. .map should work for Array subclasses, preserving class
>
>
> are you changing that position?

That's probably not me who said it :-)

> Also, there is another subtlety that is on slide 25 of the deck I
> present.  Existing ES<6 code may create objects that inherit from
> Array.prototype. When running on an ES6 implementation uses of
> Array.prototype.map (etc.) in such code can't change their behavior.

I am not TC39 member, so I did not see that slide, but if you say ".map 
always produces Array", it does not change the behaviour.

Could you elaborate more, please?

> So, the selection of the result "class" can't be based solely on the
> [[Prototype]]  inheritance chain.
>
>
>> - to leave Array.from (as well as Map.from, V.from etc.) as is,
>> generator comprehension does the mapping for you if you wish one.
>>
>> So, the examples would be
>>
>> V.from(x for x in new V); // you say you want the results in V
> I don't understand?  This produces the same result as new V; but with
> an extra V allocation, creation of a generator, etc.

It was rewrite of Claus' example you were discussing about:

   class V extends Array { ... }
   m = (new V()).map(val => val);
   console.log( m instanceof V ); // false

> Another issue, is that some array-like "classes" instances must have
> their size fixed at allocation. This is the case for all the
> TypedArrays.  For iterators automatically derived from most arrays,
> we can make the size information available.  But for a generator,
> there is no way to know how many iterations it will make without
> actually running it.   For specification purposes, we may specify the

Hm. Yes, this is problem, then.

> "from" method as accumulating the element values into a List,
> allocatininge most TypedArray uses) that the double copy can be
> optimized away.  That means that in the usual case the size must be
> available at the beginning which precludes using a generator
> expression as the usual case pattern.

Yes, then the second point is not-starter.

But I still think it is simpler to specify ".map" returning array, 
always. You know you get an Array, you don't have to worry about magic 
of Set, Map etc., if you wish to have it in other kind of container, use 
Container.from(...).

Of course, I don't know what that slide 25 was about, but for now I 
argue map is different from concat, filter etc. do not transform 
contents, just manipulate containers.

> Allen

Herby


More information about the es-discuss mailing list