forEach on next

Kris Kowal kris.kowal at cixar.com
Sun Mar 28 17:10:41 PDT 2010


[moving this thread onto es-discuss]

On Tue, Mar 23, 2010 at 2:45 PM, Brendan Eich <brendan at mozilla.org> wrote:
> On Mar 23, 2010, at 2:17 PM, Kris Kowal wrote:
>
>> Aside: I hope we can resolve MarkM's suspicions of composability
>> problems with generators; they are one of my very favorite features of
>> Python: like UNIX pipes, composability is their middle-name.  The PEP
>> he referenced some time ago just provides more terse syntax for
>> chained generators; I find that this is a nicety but not a
>> demonstration that the simple "yield" is flawed.
>
> Yes, just because something doesn't sing and dance  doesn't mean it is not a
> good actor ;-).
>
>> I also hope that
>> ECMAScript opts to follow the Python iterator protocol more closely
>> than JavaScript 1.6—for chained lazy iterations, "next" needs to be
>> the most discrete layer of the protocol, with "forEach" implemented in
>> terms thereof.
>
> JS1.6 was forEach and other Array extras.
>
> JS1.7 introduced generators and iterators, and yes, we didn't incompatibly
> change the Array extras to treat iterators as arrays. We also didn't
> introduce new libraries, e.g. Python itertools workalikes. It's easy enough
> to do this in user-land, and hard for the TC39 committee to get  library
> design right.

Thanks for the clarification.

> At this point how would you make forEach and other Array extras work on
> iterators?

I'm getting all sorts of alarms going off in my head to the tune of
"this is all obvious; I probably missed something important. Like,
this is how it works already." I've heard complaints about for each
loops stalling to collect though, so here are my thoughts about
iterators anyway:

I was just looking at some transcoding stream stuff, which follows the
general form of Python's iterator protocol.  The notion is that "next"
is the most atomic unit of the iterator protocol; if you have an
object that implements "iterator", that returns an object that
implements "next", you get "forEach" and friends for free.  This is
important because "next" is "pausable" (or progress on explicit
request, really), and "forEach" is not.  This means that you can
create incrementally iterable generics like "mapIterator" and thereby
create chains of decorated iterators that can operate on iterations of
indefinite length, and "forEach" doesn't have to collect the values of
the iterable before entering its loop.

/***
 * @this {Object}
 */
SomethingAutoIterable.prototype.iterator = function () {
    return this;
};

/***
 * @this {{iterator}} any iterable object.  `iterator` must
 * return an object with a `next` method that returns the
 * next element of the iteration or throws `StopIteration`.
 */
SomethingAutoIterable.prototype.forEach = function (block, that) {
    var line;
    var iterator = this.iterator();
    while (true) {
        try {
            line = iterator.next();
        } catch (exception) {
            if (exception === StopIteration)
                break;
            throw exception;
        }
        block.call(that, line);
    }
};

If you're crazy, can optimize the crap out of the try/catches
(presumably by removing them for a small set of common types), and
want to take things one step further than Python, you can implement
both "continue" and "break" semantics by adding SkipIteration.

…forEach = function (relation, that) {
    var iterator = this.iterator();
    try {
        while (true) {
            try {
                relation.call(that, iterator.next());
            } catch (exception) {
                if (exception !== SkipIteration) {
                    throw exception;
                }
            }
        }
    } catch (exception) {
        if (exception !== StopIteration) {
            throw exception;
        }
    }
};

And, if you're *really* crazy, you can implement breaking and
continuing outer loops by associating individual StopIteration and
SkipIteration instances with each iterator. By really crazy, I mean
that my PEP got shot down, so I wouldn't be surprised by a repeat
success.

Kris Kowal


More information about the es-discuss mailing list