I hope these [lies and oversimplifications] will help others understand coroutines. See below for an increasingly accurate explanation. A special thanks to miguel on the #tcl freenode channel for taking the time to explain this to me. ====== proc allNumbers {} { yield set i 0 while 1 { yield $i incr i 2 } } coroutine nextNumber allNumbers for {set i 0} {$i < 10} {incr i} { puts "received [nextNumber]" } rename nextNumber {} ====== The output of the above code is: ====== received 0 received 2 received 4 received 6 received 8 received 10 received 12 received 14 received 16 received 18 ====== The first thing to understand is the [yield] command (which is in the coroutine's code). [[yield $foo]] acts like [[return $foo]], but it suspends execution; when execution is resumed, the proc restarts on the line after the previous call to yield. The procedure "allNumbers" is a proc which first calls [yield], and so suspends immediately (line 2); when it resumes it begins execution at line 3, after which it reaches another [yield] within a while loop on line 5. After producing each number, it yields its value ... and suspends until it is called again. Now this line: ====== coroutine nextNumber allNumbers ====== This line will (a) run allNumbers until the first [yield] (b) create a command called 'nextNumber' that resumes execution of allNumbers when nextNumber is called. So after this we have allNumbers suspended right before 'set i 0', and a new command 'nextNumber' that continues it where it left off. Get it? ---- ''[MS] notes that he kind of lied to jblz: [yield] is a bit more complicated, but behaves exactly as described for this example.'' ---- [ZB] Wrong. It's the thing, that once confused me: the proc restarts not "on the line after previous call to yield", but resumes - one can say - directly in that lately left yield field, because there it can get ev. arguments "from outside". Consider the yield field as a "gate". You're leaving the proc - and getting back using this gate. Changed an example a bit - in my opinion, now it better explains the role of yield; changing theValue (and restarting the loop) one can see, how the increment step is different. ====== proc allNumbers {} { yield set i 0 while 1 { set howMuch [yield $i] incr i $howMuch } } coroutine nextNumber allNumbers set theValue 2 for {set i 0} {$i < 10} {incr i} { puts "received [nextNumber $theValue]" } ======