Array iterator questions

# Jason Orendorff (13 years ago)
  1. The current draft spec has Array.prototype.@@iterator() behaving like .values(), so:

    for (x of ["a"]) print(x);

would print the pair ["0", "a"].

The proposal had Array iterators producing values only by default. Why the change?

(It seems like it could be a typo, or it could be motivated by a desire for consistency across all collections. If the latter, Map should change, not Array.)

  1. According to 15.4.6.2.2, the iterators produced by Array.prototype.keys and .items will expose the index values as strings. Why strings? Don't numbers make more sense?
# Brendan Eich (13 years ago)

Jason Orendorff wrote:

  1. The current draft spec has Array.prototype.@@iterator() behaving like .values(), so:

    for (x of ["a"]) print(x);

would print the pair ["0", "a"].

The proposal had Array iterators producing values only by default. Why the change?

This came up two days ago at the TC39 meeting. It's a drafting error.

(It seems like it could be a typo, or it could be motivated by a desire for consistency across all collections. If the latter, Map should change, not Array.)

There is some desire, which motivated Allen's Array.prototype.{keys,values,items} additions in the latest draft, to have self-polymorphic method dispatch for implementing {keys,values,items}.

This led to a discussion that concluded by separating the method naming scheme and standard troika (and Andreas Rossberg proposed entries not items, which everyone thought better), from the generic object-reflection function troika that return iterators for property keys, values, and [key, value] pairs. We argued about whether the two name-troikas should match, and I think ended up allowing for this.

Dave had a suggestion for adding a bit of "dict" veneer to the generic functions in a standard module, but I'll let him 'splain that.

  1. According to 15.4.6.2.2, the iterators produced by Array.prototype.keys and .items will expose the index values as strings. Why strings? Don't numbers make more sense?

Agreed these should not coerce to string.

# Rick Waldron (13 years ago)

On Sun, Dec 2, 2012 at 12:58 AM, Brendan Eich <brendan at mozilla.org> wrote:

Jason Orendorff wrote:

  1. The current draft spec has Array.prototype.@@iterator() behaving like .values(), so:

    for (x of ["a"]) print(x);

would print the pair ["0", "a"].

The proposal had Array iterators producing values only by default. Why the change?

This came up two days ago at the TC39 meeting. It's a drafting error.

(It seems like it could be a typo, or it could be motivated by a desire

for consistency across all collections. If the latter, Map should change, not Array.)

There is some desire, which motivated Allen's Array.prototype.{keys,values, **items} additions in the latest draft, to have self-polymorphic method dispatch for implementing {keys,values,items}.

This led to a discussion that concluded by separating the method naming scheme and standard troika (and Andreas Rossberg proposed entries not items, which everyone thought better), from the generic object-reflection function troika that return iterators for property keys, values, and [key, value] pairs. We argued about whether the two name-troikas should match, and I think ended up allowing for this.

Dave had a suggestion for adding a bit of "dict" veneer to the generic functions in a standard module, but I'll let him 'splain that.

I was mid-write up for this, but Brendan covered it more succinctly (thank you). I'll just add that the discussion, including resolution and consensus will be published on Monday along with all three days of meeting notes. I plan to file all of the resolutions as tickets on bugs.ecmascript.org tomorrow, so I suspect that Allen will have all of the changes in the next revision (barring unforeseen specification related issues).

# Brandon Benvie (13 years ago)

When you say polymorphic dispatch with to items(entries)/keys/values, you're saying the caller helps determine which is used? This would make sense and resolve issues I've had. The generic array iterator really helps to put a fine point on the limitations of using any single default iteration type, as none are universally appropriate. Some callers derive value from [index, value] but many just want value.

# Brendan Eich (13 years ago)

Brandon Benvie wrote:

When you say polymorphic dispatch with to items(entries)/keys/values, you're saying the caller helps determine which is used?

The caller, specifically the receiver bound to |this|, the base object of the "callee" reference-type expression to the left of the ( starting the actual parameter list, yes.

# Brandon Benvie (13 years ago)

Er yeah I guess caller wasn't really the right term, but that's what I meant.

# Allen Wirfs-Brock (13 years ago)

On Dec 1, 2012, at 8:14 AM, Jason Orendorff wrote:

  1. The current draft spec has Array.prototype.@@iterator() behaving like .values(), so:

    for (x of ["a"]) print(x);

would print the pair ["0", "a"].

The proposal had Array iterators producing values only by default. Why the change?

(It seems like it could be a typo, or it could be motivated by a desire for consistency across all collections. If the latter, Map should change, not Array.)

Note, there is a margin note on of 15.4.4.26 that hi-lites "items" and says "Or should this be values". There are a lot of notes like this in the draft. They are requests for knowledgable reviews to check spec. language that is uncertain for some reason.

  1. According to 15.4.6.2.2, the iterators produced by Array.prototype.keys and .items will expose the index values as strings. Why strings? Don't numbers make more sense?

It does that because array index keys are exposed as strings everywhere else.

There is no specific definition (that I can find) of the keys iterator for arrays in the wiki proposal. There is only the general @iter.keys function which is defined in terms of for-in and hence returns string property keys.

However, I don't have any objection to return integer keys in this case.

# Allen Wirfs-Brock (13 years ago)

On Dec 1, 2012, at 9:58 PM, Brendan Eich wrote:

Jason Orendorff wrote:

  1. The current draft spec has Array.prototype.@@iterator() behaving like .values(), so:

    for (x of ["a"]) print(x);

would print the pair ["0", "a"].

The proposal had Array iterators producing values only by default. Why the change?

This came up two days ago at the TC39 meeting. It's a drafting error.

(It seems like it could be a typo, or it could be motivated by a desire for consistency across all collections. If the latter, Map should change, not Array.)

There is some desire, which motivated Allen's Array.prototype.{keys,values,items} additions in the latest draft, to have self-polymorphic method dispatch for implementing {keys,values,items}.

This led to a discussion that concluded by separating the method naming scheme and standard troika (and Andreas Rossberg proposed entries not items, which everyone thought better), from the generic object-reflection function troika that return iterators for property keys, values, and [key, value] pairs. We argued about whether the two name-troikas should match, and I think ended up allowing for this.

A related issue is which iterator to select in various contexts. For example, if @iterator returns values for arrays and entry key/value pairs for maps then using @iterator may not be the best choice for, for example, processing the argument of Array.from.

Basically, iteration clients need to know what they are asking for. If you are going to write for (i of x) doSomething(x,i);

You better have the expected @iterator behavior of x pretty locked down

If you known you want "values" and aren't sure of the actual "class" of x then you should probably write: for (i of x.values()) doSomething(x,i);

and let it break if x doesn't have a values method.

For things like Array.from and spread, a fall back sequences is a possible approach: 1) if obj has a "values" method us it to get the iterator 2) else if obj as a @iterator method use it to get the iterator 3) else do an array like iteration using the obj's length property value.

I've already been butting into these kinds of situations when specify handling the optional argument to the Map and Set constructors. It's also the reason I have been slow to update the Array.from spec. to handle anything other than array-likes. Map really wants key value pairs so calling @iterator on an Array, if it returns values, isn't what it should do. However, Set really wants only values. In general, when dealing with generic collections you can't just use @iterator. You need to be more explicit about whether you expect to process keys, values, or both.

# Rick Waldron (13 years ago)

On Sun, Dec 2, 2012 at 2:47 PM, Allen Wirfs-Brock <allen at wirfs-brock.com>wrote:

On Dec 1, 2012, at 8:14 AM, Jason Orendorff wrote:

snip

  1. According to 15.4.6.2.2, the iterators produced by Array.prototype.keys and .items will expose the index values as strings. Why strings? Don't numbers make more sense?

It does that because array index keys are exposed as strings everywhere else.

There is no specific definition (that I can find) of the keys iterator for arrays in the wiki proposal. There is only the general @iter.keys function which is defined in terms of for-in and hence returns string property keys.

However, I don't have any objection to return integer keys in this case.

+1

Users will take this for granted and assume the index value is going to be a number since map, forEach, filter, every, some and reduce all pass a number as the index argument and for-loops increment a number.

# Brendan Eich (13 years ago)

Yes, we should have a new covenant that avoids adding stringized array indexes for new APIs. New APIs need to turn down the arrays-are-objects setting JS had from 1.0 (JS1 in 1995 had something even more object-like: objects equated indexes to property names added in creation order! See DOM forms/elements/links array-likes where elements can have aliasing names depending on markup...).

# Brandon Benvie (13 years ago)

This discussion brings iterator protocol back into play for spread no?

# Brendan Eich (13 years ago)

Rick's notes cover it, but yes, the resolution is:

  1. Array.from tests @iterator falls back on array-like (for polyfillability).

  2. Spread uses iteration protocol (tests @iterator) only.

  3. All for-of forms match (2) and use iteration protocol only.