Within the context, values may be generated as results by using the yield command; if no value is supplied, the empty string is used. When that is called, the context will suspend execution and the coroutine command will return the argument to yield. The execution of the context can then be resumed by calling the context command, optionally passing in the value to use as the result of the yield call that caused the context to be suspended. If the coroutine context never yields and instead returns conventionally, the result of the coroutine command will be the result of the evaluation of the context.
The coroutine can also be deleted by destroying the command name, and the name of the current coroutine can be retrieved by using info coroutine. If there are deletion traces on variables in the coroutine's implementation, they will fire at the point when the coroutine is explicitly deleted (or, naturally, if the command returns conventionally).
At the point when command is called, the current namespace will be the global namespace and there will be no stack frames above it (in the sense of upvar and uplevel). However, which command to call will be determined in the namespace that the coroutine command was called from.
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 {}
In this example, the coroutine acts to add up the arguments passed to it.
coroutine accumulator apply {{} { set x 0 while 1 { incr x [yield $x] } }} for {set i 0} {$i < 10} {incr i} { puts "$i -> [accumulator $i]" }
This example demonstrates the use of coroutines to implement the classic Sieve of Eratosthenes algorithm for finding prime numbers. Note the creation of coroutines inside a coroutine.
proc filterByFactor {source n} { yield [info coroutine] while 1 { set x [$source] if {$x % $n} { yield $x } } } coroutine allNumbers apply {{} {while 1 {yield [incr x]}}} coroutine eratosthenes apply {c { yield while 1 { set n [$c] yield $n set c [coroutine prime$n filterByFactor $c $n] } }} allNumbers for {set i 1} {$i <= 20} {incr i} { puts "prime#$i = [eratosthenes]" }
proc report {where level} { # Where was the caller called from? set ns [uplevel 2 {namespace current}] yield "made $where $level context=$ns name=[info coroutine]" } proc example {} { report outer [info level] } namespace eval demo { proc example {} { report inner [info level] } proc makeExample {} { puts "making from [info level]" puts [coroutine coroEg example] } makeExample }
Which produces the output below. In particular, we can see that stack manipulation has occurred (comparing the levels from the first and second line) and that the parent level in the coroutine is the global namespace. We can also see that coroutine names are local to the current namespace if not qualified, and that coroutines may yield at depth (e.g., in called procedures).
making from 2 made inner 1 context=:: name=::demo::coroEg