Re: Why can’t for-of be applied to iterators?

Allen Wirfs-Brock allen at wirfs-brock.com
Sun Jun 9 08:30:18 PDT 2013


On Jun 9, 2013, at 2:34 AM, Jason Orendorff wrote:

> On Sun, Jun 9, 2013 at 2:17 AM, Axel Rauschmayer <axel at rauschma.de> wrote:
> > Another use case for iterator support: retrieve the first element from an iterator, then iterate over the remaining elements via for-of.
> 
> Right, this happens whenever you're doing a fold and your combining function has no handy "zero" value. For the sake of concreteness let's say we're writing code for a robot kitchen, and we've got a function for taking a collection of bowls and dumping all the contents into the first bowl. In Python:
> 
>     def combine(bowls):
>         iterator = iter(bowls)
>         first_bowl = next(iterator, None)
>         for bowl in iterator:
>             dump_into(bowl, first_bowl)
> 
> In JS the same function would be:
> 
>     from "yet_unspecified_standard_module" import iteratorSymbol;
> 
>     function combine(bowls) {
>         let iterator = bowls[iteratorSymbol]();
>         let {value: firstBowl, done} = iterator.next();
>         if (done)
>             return;  // no bowls at all
>         let rest = {};
>         Object.defineProperty(rest, iteratorSymbol, {value: () => iterator});
>         for (let bowl of rest)
>             dumpInto(bowl, firstBowl);
>     }
> 
> If you don't mind copying the source collection into an array, you can use destructuring instead:
> 
>     let [?first, ...rest] = bowls;
> 
> At least, I think that's the current proposed destructuring syntax/semantics. Of course this only works if the use case has a structure that the destructuring mini-language can express.
> 
> Other use cases come up too: (1) you want to process a sequence in one loop until you reach some marker, and then break out of the first loop and process the rest in another loop; or (2) you want to pass the iterator to a separate function that consumes a subsequence of the input. (For example, when the input sequence is from a file, and you're doing some light parsing.)
> 
> I think it's a mistake for iterators not to be iterable. We will have error messages like "Iterator object is not iterable", and users will say "*really*, JavaScript?". Requiring users to build pseudo-collection objects like `rest` in these use cases seems awfully bureaucratic, and hard to justify without resorting to types.

Iterators can be Iterables and any Iterator created as a generator will automatically be an Iterator.

But it really comes down to the startup behavior of for-of if the value of the |of| expression is not an Iterable.

Currently the spec. days that if it is not an Iterable the for-of loop doesn't run (although some of the details in the For In/Of Expression Evaluation looks a little bogus).  It would be easy enough to to spec. it such that if the value is not an Iterable (does not have an @@iterator property) then it just assumes that it must already be an Iterator.

in that case we could say:

    function combine(bowls) {
        let iterator = bowls[iteratorSymbol]();
        let {value: firstBowl, done} = iterator.next();
        if (done)
            return;  // no bowls at all
         for (let bowl of iterator)
            dumpInto(bowl, firstBowl);
    }

Allen
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20130609/955972e0/attachment-0001.html>


More information about the es-discuss mailing list