http://qs1969.pair.com?node_id=351555


in reply to Coroutines in Perl

Someone already metioned that Parrot will have continuations, with which implementing coroutines is exceptionally easy. (continuations can do much more than that, though - check out the pseudo-prolog syntax you can hack onto ruby, a language with native support for continuations. Scroll to the end to see it in action)

Note that usually with coroutines, at least with the implementations of two cooperating coroutines that I've seen (often done as a bunch of twisty complicated C macros), one routine will be the "driver", and will interact with the rest of the world in the normal fashion, and the other routine will be the "driven". For example, you'll have something like this:

COROUTINE(int) lucas_numbers(int x0, int x1) { int temp; COROUTINE_RETURN(x0); while(1) { COROUTINE_RETURN(x1); temp = x1; x1 = x1 + x0; x0 = temp; } } void print_n_fibonacci(int n) { while (n--) { printf "%d\n", COROUTINE_INVOKE(lucas_numbers, 1, 1); } }

In the above code, only the first routine is doing anything "strange", to our understanding. The second routine is just repeatedly invoking the first, and the first just restarts wherever it left off. Note that python's generator syntax uses a very similar style. Anyone familiar with Haskell should recognize this style too.

Note that this use of coroutines can is to some extent obsoleted (or at least, "made less necessary") by the invention of objects. It is usually obvious how to bundle the data that the coroutine is carrying around internally between invocations - in the example, this is the x0 and x1 variables - up into an object, and have the bits of code executed in-between return calls turned into one object method. However, the most straightforward implementation of the above code as an object with a single method would result in a special case for the first return value -- as we all know, ceteris paribus, more special case means more bugs.

If we now imagine some complicated process - say, some code that read input in some arbitrary character encoding and returned it in UTF-8 one byte at a time - we see that implementing the mess with objects can require several special cases. (Although at this point someone's bound to mention that this is trivial to implement via a state machine, which are wonderful things for separating out special cases)

-- @/=map{[/./g]}qw/.h_nJ Xapou cets krht ele_ r_ra/; map{y/X_/\n /;print}map{pop@$_}@/for@/