coroutine is the new main

coroutines and the event loop are a powerful combination. Together they allow multiple control flows to run in a single interpreter and to cooperate to achieve the objective of the program.

See Also

coro drive
Creates a coroutine, schedules it to evaluate a script, enters the event loop, and returns the result from the coroutine.
ycl interp main
Like tclsh, but sets up a main coroutine, but everything happens inside a coroutine.
update considered harmful
Wisdom on working in a concurrent world. coroutines can help avoid the issue of entering the event loop multiple times, but the issue of critical sections is one the programmer will need pay careful attention to in order to maintain sanity.


In a Tcl script, it's a good idea to place the main script into a procedure, and many programmers are in the habit of doing something like this:

proc main {argv0 argv} {
    # The main script
main $argv0 $argv

In Coroutines for event-based programming, NEM noted the utility of making a main routine a coroutine. As coroutines take deeper root in the Tcl ecosystem, if third-party commands can assume they're called in a coroutine context, they can take advantage of that fact to yield from the coroutine at opportune moments, allowing other activities in the system to continue on in the meantime. This development will be in large part transparent to the script that considers itself the only control flow in the program. All that's required to use such third-party commands is that the main script be structured like this:

after 0 [list coroutine main apply [list {argv0 argv} {
    # the main script
    exit 0 
} [namespace current]] $argv0 $argv]
vwait ::nameofsomevariablethatwillneverexist

APN My understanding is a little different. As I think miguel pointed out some time back, in addition to the above, the Tcl event loop also has to be modified to invoke event handlers via something similar to the above. The issue with this are that although the change would not be hard, it has to be done at the C level in the Tcl core and cannot be done via script.

aspect: Another wrinkle is that not all coroutines can yield to the event loop! For instance, Generators in Tcl must yield values, and only be resumed by their consumer. Inadvertently calling code that assumes yield means suspend from within a generator is bad news.

PYK 2016-04-18: I don't understand the part about this having to be done at the C level. Take randbits on the random number page for example. It works fine under this script-level main coroutine. It's true that a coroutine that wants to yield a value can't itself call third-party commands that expect to yield to the event loop. Such commands will have to avoid commands like randbits. I think yielding to the event loop is an important enough feature that it would be best to forego the yield-as-a-generator pattern in favor of synchronizing request-response systems like this one that I recently wrote.

APN The C level comment is in response to your statement above third-party commands can assume they're called in a coroutine context.... The point being that unless the event loop invokes callbacks via a coroutine, third party commands cannot assume they are in a coroutine context. Unless you expect all callbacks registered with the event loop to be explicitly wrapped with coroutines.

PYK: I see. I was just talking about using something like coroutine main ... at the script level. Haven't given much thought to what you're describing. I guess that would be a true everything is a coroutine environment. Maybe in that case Tcl could ditch proc. Sounds interesting.