Brendan Eich (2013-04-30T14:24:30.000Z)
Andy Wingo wrote:
> Hi Brendan,
>
> On Tue 30 Apr 2013 09:47, Brendan Eich<brendan at mozilla.com>  writes:
>
>> js>  o.close()
>> typein:5:0 TypeError: yield from closing generator function foo() {
>> typein:5:0   try {
>> typein:5:0     yield 1;
>> typein:5:0   } finally {
>> typein:5:0     yield 2;
>> typein:5:0   }
>> typein:5:0 }
>
> For the record, this behavior is not specified in harmony:generators.
> Also it seems to me to be an unnecessary restriction that originated in
> Python's desire to always run the finally blocks -- not a goal of ES6.

You're right, this seems a hold-over from six or seven years ago.

>>> Incidentally, close() is not the same as forcing a return:
>>>
>>>       >>>   def bar():
>>>       ...   try:
>>>       ...     return 1
>>>       ...   finally:
>>>       ...     yield 2
>>>       ...
>>>       >>>   bar().__next__()
>>>       2
>> That does not show close in action, though. The generator-iterator runs
>> once there, yielding 2.
>
> Sure.  I just mean to say that close introduces some mental
> complication.  "A yield expression can produce a value or throw an
> expression.  Except when close() is called, in which case it's like a
> return.  But not quite like a return."  The spec would be better without
> the last two sentences IMO.

The generator can't close itself, though, so this is not an issue:

js> function foo() { yield 1; gen.close() }
js> gen = foo()
({})
js> gen.next()
1
js> gen.next()
typein:6:26 TypeError: already executing generator

But not to worry, you've convinced me on other grounds!

>>> Python's use case is also different because it specifies that when the
>>> generator object is finalized, the close() method gets called --
>>> certainly something we don't want to do for ES6.
>> Quite. Long-ago es4-discuss threads covered all of this.
>>
>> https://mail.mozilla.org/pipermail/es-discuss/2006-December/
>> https://mail.mozilla.org/pipermail/es-discuss/2007-January/
>>
>> Look for "Immediate closing of iterators".
>
> If a generator runs to completion, there is no need to close it -- the
> operation is a no-operation.
>
> A bug mentioned in that discussion:
>
>    https://bugzilla.mozilla.org/show_bug.cgi?id=349326
>
> seems to suggest that you expect close() to be called when the generator
> is collected, which again is not an ES6 thing.

Wow, thanks for the memories! That code is long gone. SpiderMonkey does 
not do anything from finalization or other GC phases that unprivileged 
(read: not the debugger) code can observe.

Just so you don't have to deep-dive so vigilantly: everyone agrees we 
should not expose pre- or post-mortem finalizers -- in JS.

>>> ES6 certainly won't provide a guarantee that finally blocks will run, so
>>> it seems to me that the main reason for close() is gone.
>> The JS1.7 prototype for ES4 ran close automatically only from for-in
>> (which evolved into ES6's for-of). That's still on the table.
>
> Though yield* is currently specified to call close(), I don't believe
> that close() is in the for-of spec.

D'oh. Another gap in the wiki, fixable, but again: you've convinced me. 
Easier to drop close.

>> See above. Automating generator close from for-of is straightforward:
>>
>> js>  function foo() {
>>    try {
>>      yield 1;
>>    } finally {
>>      print("glorp");
>>    }
>> }
>> js>  for (let x of foo()) print(x)
>> 1
>> glorp
>
> This doesn't require close() at all to work!  Did you have another
> example in mind?

I did, sorry -- forgot the break:

js> for (let x of foo()) {print(x); break}
1
glorp

The idea is to run close inevitable, for all completions of the loop. 
This is not the same as finalization. It was on the radar as an ugly 
kind of "Python with", but we have try-finally already.

> It really seems to me that this is an interface that was made because of
> Python's "always-run-the-finally-block" thing, which ES6 doesn't have.
> Because we don't have that need, it does not seem useful to me.

Agreed. Thanks for pointing this out!

/be
github at esdiscuss.org (2013-07-12T02:26:56.493Z)
Andy Wingo wrote:
> On Tue 30 Apr 2013 09:47, Brendan Eich<brendan at mozilla.com>  writes:
>
>> ```
>> js>  o.close()
>> typein:5:0 TypeError: yield from closing generator function foo() {
>> typein:5:0   try {
>> typein:5:0     yield 1;
>> typein:5:0   } finally {
>> typein:5:0     yield 2;
>> typein:5:0   }
>> typein:5:0 }
>> ```
>
> For the record, this behavior is not specified in harmony:generators.
> Also it seems to me to be an unnecessary restriction that originated in
> Python's desire to always run the `finally` blocks -- not a goal of ES6.

You're right, this seems a hold-over from six or seven years ago.

>>> Incidentally, `close()` is not the same as forcing a return:
>>>
>>>       >>>   def bar():
>>>       ...   try:
>>>       ...     return 1
>>>       ...   finally:
>>>       ...     yield 2
>>>       ...
>>>       >>>   bar().__next__()
>>>       2
>> That does not show close in action, though. The generator-iterator runs
>> once there, yielding 2.
>
> Sure.  I just mean to say that close introduces some mental
> complication.  "A `yield` expression can produce a value or throw an
> expression.  Except when `close()` is called, in which case it's like a
> `return`.  But not quite like a `return`."  The spec would be better without
> the last two sentences IMO.

The generator can't close itself, though, so this is not an issue:

```
js> function foo() { yield 1; gen.close() }
js> gen = foo()
({})
js> gen.next()
1
js> gen.next()
typein:6:26 TypeError: already executing generator
```

But not to worry, you've convinced me on other grounds!

>>> Python's use case is also different because it specifies that when the
>>> generator object is finalized, the `close()` method gets called --
>>> certainly something we don't want to do for ES6.
>> Quite. Long-ago es4-discuss threads covered all of this.
>>
>> https://mail.mozilla.org/pipermail/es-discuss/2006-December/
>> https://mail.mozilla.org/pipermail/es-discuss/2007-January/
>>
>> Look for "Immediate closing of iterators".
>
> If a generator runs to completion, there is no need to close it -- the
> operation is a no-operation.
>
> A bug mentioned in that discussion:
>
> https://bugzilla.mozilla.org/show_bug.cgi?id=349326
>
> seems to suggest that you expect `close()` to be called when the generator
> is collected, which again is not an ES6 thing.

Wow, thanks for the memories! That code is long gone. SpiderMonkey does 
not do anything from finalization or other GC phases that unprivileged 
(read: not the debugger) code can observe.

Just so you don't have to deep-dive so vigilantly: everyone agrees we 
should not expose pre- or post-mortem finalizers -- in JS.

>>> ES6 certainly won't provide a guarantee that finally blocks will run, so
>>> it seems to me that the main reason for `close()` is gone.
>> The JS1.7 prototype for ES4 ran `close` automatically only from `for`-`in`
>> (which evolved into ES6's `for`-`of`). That's still on the table.
>
> Though `yield*` is currently specified to call `close()`, I don't believe
> that `close()` is in the `for`-`of` spec.

D'oh. Another gap in the wiki, fixable, but again: you've convinced me. 
Easier to drop `close`.

>> See above. Automating generator close from `for`-`of` is straightforward:
>>
>> ```
>> js>  function foo() {
>>    try {
>>      yield 1;
>>    } finally {
>>      print("glorp");
>>    }
>> }
>> js>  for (let x of foo()) print(x)
>> 1
>> glorp
>> ```
>
> This doesn't require `close()` at all to work!  Did you have another
> example in mind?

I did, sorry -- forgot the break:

```
js> for (let x of foo()) {print(x); break}
1
glorp
```

The idea is to run `close` inevitable, for all completions of the loop. 
This is not the same as finalization. It was on the radar as an ugly 
kind of "Python with", but we have `try`-`finally` already.

> It really seems to me that this is an interface that was made because of
> Python's "always-run-the-`finally`-block" thing, which ES6 doesn't have.
> Because we don't have that need, it does not seem useful to me.

Agreed. Thanks for pointing this out!