Size: 2352
Comment: more text
|
Size: 2382
Comment: comments in example code
|
Deletions are marked like this. | Additions are marked like this. |
Line 30: | Line 30: |
cc.send(undefined); // start the generator. no args allowed cc.send(cc); |
cc.send(undefined); // start the generator. (no args allowed) cc.send(cc); // it's almost like call/cc! |
To-do.
The most cogent plain-language definition of coroutine that I have encountered is this: a coroutine is just a function with multiple entry and exit points.
The first prerequisite to understanding how Conkeror's coroutine library works is to read and grok everything about generators in the MDC article, New in JavaScript 1.7. Generators are the JavaScript primitive that makes it possible to suspend execution, and is thus the basic requirement for implementing coroutines in JavaScript.
Next, read MinibufferReadWalkthrough. We'll be referring to it as an example throughout this article.
JavaScript has the same kind of generators as Python, and in the Python world, they are called enhanced generators. (Because prior to Python 2.5, Python had a more limited implementation.)
With a coroutine, not only can the original called function yield, but any function it calls in turn (and any function to any depth in the call chain) can also yield.
With generators, only the originally called function can yield.
Emulating coroutines on top of generators is the point of Conkeror's coroutine library. The technique is called trampolining.
In a trampoline-coroutine system, a coroutine-thread is a stack of generators.
Recall from MinibufferReadWalkthrough the pair (yield CONTINUATION) and yield SUSPEND. Before suspending, the coroutine needed to get a reference to its own continuation, to stash somehwere where a later event could use it to resume the suspended thread. The special loop is running inside the coroutine thread, orchestrating the proper stacking of the generators. In effect, the special loop needed to have on hand a reference to its own continuation, in order to send back to any generator that performed (yield CONTINUATION). But generators are a far cry from call/cc. You can't call a generator with its own continuation as a parameter. However, what you can do is this: after starting the generator, have an extra yield, so that you can send the contination into it.
function my_generator () { var cc = yield; while (true) { // yield values here } } var cc = my_generator(); cc.send(undefined); // start the generator. (no args allowed) cc.send(cc); // it's almost like call/cc!