What are the desired semantics of forEach for iterables?

The current spec is at http://heycam.github.io/webidl/#es-forEach but 
clearly has some problems.

Specifically, we need to answer the following questions:

1)  For two-type iterables, what should be passed as arguments to the 
callback function?  The obvious answer seems to be "value, key, this", 
with the index not passed at all.

2)  For one-type iterables, what should be passed as arguments to the 
callback function?  The two possible answers are "value, value, this" 
and "value, index, this"; the former matches Set and the latter matches 
Array.  The only one-type iterable I'm aware of shipping so far in 
browsers is DOMTokenList in Chrome, and this has the arraylike behavior, 
but it's also got an indexed getter so might be a special case anyway...

3)  How should deletion and addition during iteration, especially 
deletion be handled?  The two possible answers are:
   a) forEach starts an index at 0, increments it as it goes, uses that
      to index into the list, stops when the index is greater than the
      list length.  This means values can get skipped when an entry
      that's already had forEach called on it is deleted.
   b) forEach takes a list and ensures that all entries that were in it
      before start and aren't deleted during the forEach callbacks, as
      well as all entries added during forEach callbacks, get a callback.

Behavior (a) is what Array does.  Behavior (b) is what Set and Map do 
(though they handwave exactly how it's supposed to work).  Note that in 
both the Array and Map cases the behavior of forEach matches the 
behavior of iterating the object and calling the callback on each value 
the iterator returns.  In the case of IDL iterables, the iterator 
behavior is the Array-like behavior, with values possibly getting skipped.

Chrome's Headers (the only two-type iterator I'm aware of anyone 
shipping so far), seems to implement behavior (a) here, based on this 
testcase:

   var h = new Headers;
   h.append("a", "b")
   h.append("c", "d")
   h.append("e", "f")
   h.forEach(function(...args) {
     console.log(args);
     h.delete("a");
   });

Chrome's DOMTokenList also seems to implement behavior (a) (though I 
personally think that it should be using Array.prototype.forEach in any 
case, since it has indexed getters, so it may not be a good testcase).

-Boris

Received on Wednesday, 21 October 2015 13:50:42 UTC