Exceptional exits from generators
A re-ping on this issue. Probably the relevant people were distracted by TC39 last week.
yes, It's on my "get back to soon" list...
+1 from me. I thought through the issue and your proposal seems to make sense.
It woulds also be good to create a bugs.ecmascript.org ticket for this. That will ensure it doesn't get lost
On Tue, Apr 8, 2014 at 7:47 AM, Andy Wingo <wingo at igalia.com> wrote:
iter.next() // => { value: undefined, done: true }
I find this very strange. I would have expected an exception of the kind "generator is already running", as indeed we entered the running state but never moved out of that state.
I get what you said about there being an extra try-catch in the continuation. That's certainly true. And very likely no user will ever care how ES behaves in this case—if a generator throws, you're not meant to call back into it.
On the other hand it seems more ECMAScript-like for the execution of the generator to be considered "done" when an exception is thrown out of it. The spec has terminology like "abrupt completion" that takes that viewpoint for granted.
How expensive does that try-catch need to be? In straightforward implementations, the cost should be a single branch, well-predicted as long as exceptions are rare. Implementations with "zero-cost" exception handling would avoid that; I think you can even retain the tail-call opportunity ("tail-resume"?) in .next() and .throw().
If it is removed we could also consider removing the suspendedStart->completed state change on Generator.prototype.throw. If that were done we could remove the suspendedStart state entirely; dead spec elimination ;)
I don't think we can eliminate the test for "suspendedStart". That would mean plowing ahead with the rest of the algorithm, right? But the generator's [[GeneratorContext]] slot holds undefined; we can't resume it. It would be consistent with your idea to replace the suspendedStart->completed state change with suspendedStart->executing.
Anyway—let's not remove suspendedStart unless we really mean to remove the special state that new generators start in. The purpose of [[GeneratorState]] is partly expository.
The current ES6 draft seems to specify that if a running generator throws an exception, that its state moves to "completed". It seems to specify this in §25.3.3.1,
GeneratorStart
. (Oddly, the procedure described inGeneratorResume
can return toGeneratorStart
; spec strangeness). Anyway, that means that:function *foo() { yield 1; yield 2 } var iter = foo() iter.next() // => { value: 1, done: false } iter.throw(42) // uncaught exception: 42
Up to here all good. And then we have, according to the spec:
iter.next() // => { value: undefined, done: true }
I find this very strange. I would have expected an exception of the kind "generator is already running", as indeed we entered the running state but never moved out of that state.
I think that nonlocal exits from within generators should not move the state to "completed", and should leave them as "suspendedStart". Beyond a subjective impression of strangeness, which not all may share, this part of the specification requires that the continuation of all GeneratorResume() invocations include a try/catch to set the generator state to "completed" if the activation resumes and then exits nonlocally.
Of course using "iter.throw" is the easy way to cause an exception, but it could happen within some function called by the generator. But if we decide to remove the try/catch from around the GeneratorResume, it might make sense to also remove the suspendedStart -> completed transition
that is special-cased in Generator.prototype.throw.
In summary: the completed-on-exception state change is of little utility but causes overhead in generator implementations in the form of the mandatory try/catch around GeneratorResume and so it should be removed IMO.
If it is removed we could also consider removing the suspendedStart->completed state change on Generator.prototype.throw. If
that were done we could remove the suspendedStart state entirely; dead spec elimination ;)
WDYT?