[Tim]
OK. So how do you feel about coroutines? Would sure be nice to have *some* way to get pseudo-parallel semantics regardless of OS.
[David Ascher]
I read about coroutines years ago on c.l.py, but I admit I forgot it all. Can you explain them briefly in pseudo-python?
How about real Python? http://www.python.org/tim_one/000169.html contains a complete coroutine implementation using threads under the covers (& exactly 5 years old tomorrow <wink>). If I were to do it over again, I'd use a different object interface (making coroutines objects in their own right instead of funneling everything through a "coroutine controller" object), but the ideas are the same in every coroutine language. The post contains several executable examples, from simple to "literature standard". I had forgotten all about this: it contains solutions to the same "compare tree fringes" problem Sam mentioned, *and* the generator-based building block I posted three other solutions for in this thread. That last looks like: # fringe visits a nested list in inorder, and detaches for each non-list # element; raises EarlyExit after the list is exhausted def fringe( co, list ): for x in list: if type(x) is type([]): fringe(co, x) else: co.detach(x) def printinorder( list ): co = Coroutine() f = co.create(fringe, co, list) try: while 1: print co.tran(f), except EarlyExit: pass print printinorder([1,2,3]) # 1 2 3 printinorder([[[[1,[2]]],3]]) # ditto x = [0, 1, [2, [3]], [4,5], [[[6]]] ] printinorder(x) # 0 1 2 3 4 5 6 Generators are really "half a coroutine", so this doesn't show the full power (other examples in the post do). co.detach is a special way to deal with this asymmetry. In the general case you use co.tran all the time, where (see the post for more info) v = co.tran(c [, w]) means "resume coroutine c from the place it last did a co.tran, optionally passing it the value w, and when somebody does a co.tran back to *me*, resume me right here, binding v to the value *they* pass to co.tran ). Knuth complains several times that it's very hard to come up with a coroutine example that's both simple and clear <0.5 wink>. In a nutshell, coroutines don't have a "caller/callee" relationship, they have "we're all equal partners" relationship, where any coroutine is free to resume any other one where it left off. It's no coincidence that making coroutines easy to use was pioneered by simulation languages! Just try simulating a marriage where one partner is the master and the other a slave <wink>. i-may-be-a-bachelor-but-i-have-eyes-ly y'rs - tim