Always close iterators?

Bergi a.d.bergi at web.de
Wed Mar 25 19:19:49 UTC 2015


Axel Rauschmayer wrote:
> Given that redundant calls to `return()` don’t make a difference (h/t Bergi)

I'm sorry, that was not 100% accurate. I only referred to `.return(x)` 
returning {done:true, value:x} and `.throw(e)` being equivalent to 
`throw e;` when the generator was never started or is already completed 
(http://people.mozilla.org/~jorendorff/es6-draft.html#sec-generatorresumeabrupt).
In fact, there are generators that behave differently when being 
prematurely aborted and attempted to be closed multiple times.
A contrived example:

   function* unstoppableCounter(n) {
        try {
            while (true)
                yield n++;
        } finally {
            console.log("unclosable!");
            yield* unstoppableCounter(n);
        }
    }

    var counter = unstoppableCounter(0);
    var i=5;
    for (var x of counter) {
        console.log(x);
        if (!--i) break;
    }
    i=4;
    for (var x of counter) {
        console.log(x);
        if (!--i) break;
    }

Every call of `counter.return()` here would actually log "unclosable!", 
increase the counter and yield {done:false, value:…} - in general, might 
have side effects. So we shouldn't do it arbitrarily often.

 > couldn’t the iteration protocol be simpler if iterators were always 
closed. “Manually implemented” iterators could be written without the 
check in line (A)

I don't think that's how an explicit iterator would be written. 
Shouldn't it look more like

   …
   next() {
       if (iterationIsDone()) {
           cleanUp();
           return {done: true};
       } else {
           return {value: nextValue(), done: false};
       }
   }

Of course that assumes that we don't have a return value, and `next()` 
is no more called after it returned `done: true` once (otherwise we'd 
clean up multiple times).
Maybe better:

   …
   next() {
       if (iterationIsDone()) {
           return {done: true};
       } else {
           let result = {value: nextValue(), done: iterationIsDone()};
           if (result.done) cleanUp(); // (B)
           return result;
       }
   }

Admittedly, that has the line you argued against again…

  Bergi


More information about the es-discuss mailing list