d at domenic.me (2015-04-14T22:10:18.650Z)
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:
```js
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
```js
…
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:
```js
…
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…d at domenic.me (2015-04-14T22:09:53.904Z)
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:
```js
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…
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