4 ms·
I'm glad javascript people are excited about generators, but I must warn - generators are not a replacement for real coroutines. Most importantly - generators
by majke 14y ago
I'm glad javascript people are excited about generators, but I must warn - generators are not a replacement for real coroutines.
Most importantly - generators don't compose.
(I'm talking about python-style generators, the type of generators javascript adapted.)
To give you an idea of what I mean:
second_sound = coroutine(function() {
yield;
console.log('Tick!');
yield;
console.log('Tock!');
});
hour_sound = coroutine(function() {
yield second_sound();
console.log('Ding dong!')
});
It's pretty obvious what programmer wants to achieve. But with generators you can't call "yield" from deeper-level function - generators are one-level-deep. The only way to compose is to 'yield' a new (deeper) generator. At this point, the caller of hour_sound() needs to understand what to do if the callee returns a generator, instead of 'null' or a valid value. And it needs to run this "deep" generator before doing 'send' on the hour_sound again.
This is just the beginning of the mess. Errors get very hard to track as tracebacks get completely unreadable. It's not easy to decide what to do when one of the nested generators throws an exception.
Python frameworks went through this long time ago, see here (look especially for the "yield" keyword): http://www.tornadoweb.org/documentation/gen.html http://www.tornadoweb.org/documentation/gen.html
Here's a bit of the underlying logic of this "simple" "coroutine-programming-syle" layer of tornadoweb:
http://www.tornadoweb.org/documentation/_modules/tornado/gen.html#engine http://www.tornadoweb.org/documentation/_modules/tornado/gen...
And here's more!
https://github.com/facebook/tornado/blob/master/tornado/gen.py#L342-L396 https://github.com/facebook/tornado/blob/master/tornado/gen....
All this magic is heavily based on the way python exceptions are integrated with generators, for example one can try to catch "StopIteration" to do a cleanup within generator. I doubt this is possible in javascript as the exceptions mechanism is much less mature.
Edit: Don't get me wrong - I love generators! But one-level-deep generators are not coroutines with stack that can be "blocked" from any deeper function.
- tuna 14y agoglad to know tornado is creating its own twisted impl.
- majke 14y agoTwisted has a similar heavy weight machinery to support generator "coroutines" :)
- eurleif 14y agoHeavy weight? It's under 40 lines of code. (The inlineCallbacks function here: http://twistedmatrix.com/trac/browser/tags/releases/twisted-8.1.0/twisted/internet/defer.py http://twistedmatrix.com/trac/browser/tags/releases/twisted-...)
- majke 14y ago"inlineCallbacks" is 3 lines long. "_inlineCallbacks" is around 50 lines long :) Let's not get into discussion if tornado is better or not than twisted. Both have similar mechanism to flatten generators and both mechanisms are much more complex than one could expect. Also, both of them heavily depend on python exception handling. BTW, this is brilliant: # This function is complicated by the need to prevent unbounded recursion # arising from repeatedly yielding immediately ready deferreds. This while # loop and the waiting variable solve that by manually unfolding the # recursion.
- pdonis 14y agoPython 3.3 fixes this with the "yield from" keyword: http://docs.python.org/3.3/whatsnew/3.3.html#pep-380 http://docs.python.org/3.3/whatsnew/3.3.html#pep-380 If Javascript did the same thing, you would write yield from second_sound(); in hour_sound, and then you could run hour_sound as a generator and it would Just Work.
- jlongster 14y agoES6 does the same thing with the `yield*` syntax.