Hacker News new | ask | show | jobs
by zedshaw 5731 days ago
There's actually a theory of what makes a complete coroutine, similar to what makes a complete closure. I don't remember all of it off the top of my head, but it's basically:

1. coroutines act as pipes that can send (yield) and receive values.

2. coroutines are first class citizens like closures so they can be passed around as values, referenced, garbage collected, etc.

3. they can yield from any point in the stack, so you can use them inside functions deeply nested without any caller N frames up from knowing about it.

4. one side of a coroutine doesn't have to know about the other side, just like functions.

5. you can inspect them to find out if they are running, suspended, etc.

I'm probably missing some things, but the gist is there's very few languages that do all of this. Lua's the only one that really gets them right and makes it easy, with probably Lisp continuations being next. I'm sure there's other languages but I know Python, Ruby, and Java really get these wrong.

I'd also say that Erlang adds one very very sexy addendum to this in that you can take any process and send it over the wire, store it, recover it, etc.

4 comments

It's probably helpful to think of coroutines as first-class functions with independent call stacks, which can be suspended and resumed (potentially returning and passing in new arguments). Coroutines are also usable as (one-shot) continuations, and continuations can be used to implement coroutines.

There's a great paper about coroutines ("Revisiting Coroutines", http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.58.4...) co-written by one of the primary Lua authors.

FWIW, you can also stream Lua functions (with string.dump), though it takes a bit of extra trouble to stream functions with nonlocal values ("upvalues"/closures). I don't know if it's possible to stream Lua coroutines, though. As with most things, Erlang's immutability makes streaming them much easier.

I believe the Coro module for Perl satisfies all of those.

http://search.cpan.org/~mlehmann/Coro-5.23/Coro.pm

Io also gets coroutines right and makes them very easy to use:

* http://www.iolanguage.com/scm/io/docs/IoGuide.html#Concurren...

* http://www.iolanguage.com/scm/io/docs/reference/Core/Core/Co...

Probably no surprise though because Lua was one of the influences behind Io design/implementation (full list of influencers from http://www.iolanguage.com/):

    * Smalltalk (all values are objects, all messages are dynamic),
    * Self (prototype-based),
    * NewtonScript (differential inheritance),
    * Act1 (actors and futures for concurrency),
    * LISP (code is a runtime inspectable/modifiable tree)
    * and Lua (small, embeddable).
I see. Python seems to lack the composability requirements of coroutines (3, 4). Thanks.

It looks as if the only way to compose coroutines in Python (say, using g inside f) would be to call `yield g.next()` every time you want to access g.next() inside f. It works, but definitely not as pretty as the real thing.