TIP #396 Version 1.4: Symmetric Coroutines, Multiple Args, and yieldto

This is not necessarily the current version of this TIP.

Title:Symmetric Coroutines, Multiple Args, and yieldto
Version:$Revision: 1.4 $
Author:Kevin Kenny <kennykb at acm dot org>
Created:Saturday, 11 February 2012
Obsoletes:TIP #372
Keywords:coroutine, yield, yieldto


A new command, yieldto, is proposed that allows a corouting to suspend its execution and tailcall into an arbitrary command. If the new command is another coroutine's resume command, we obtain symmetric coroutines. If the new command is the return command, we obtain the ability for a coroutine to present an unusual status (e.g., error, break, continue or return) to its caller. The yieldto command also marshals the arguments as a list when the yielding coroutine is next invoked, allowing for the transmission of multiple arguments.


Several TIPS (at least TIP #372, TIP #373, TIP #375, and TIP #383) have been advanced to propose various improvements to the coroutine control transfer provided by the yield command. This TIP attempts to distill the requirements of these TIPs into an irreducible minimum for implementation in 8.6 (resolving a blocking issue for an 8.6 release).

This TIP intentionally leaves out of scope some of the more complex or controversial issues, such as enhancements to info args and info default, unusual return from a `yield` operation. and code injection into coroutines. It is believed that all of these can be added later, without introducing needless incompatibilities into the basic mechanisms of coroutine construction, invocation, and yielding.

Requirements that are thought to be essential for this TIP include:

The ability for a coroutine invocation to implement any argument signature that an Tcl command can implement. A coroutine invocation must be able to accept multiple arguments, and to allow for call-by-name (or rather, call-by-quasi-value-result, see below) parameter transmission.

The ability to return an unusual status. A coroutine invocation must be able to return an error status or another unusual status (e.g., break, continue or return) to its caller, and to perform a tailcall.

Support for symmetric coroutines. Although it is well known that asymmetric coroutines (such as Tcl 8.6 implements today) and symmetric coroutines have equivalent power, the implementation of symmetric coroutines in a system that supports only asymmetric ones is possible only by coding a separate scheduler that allows an active coroutine to detach with a request to resume another. If symmetric coroutines are not implemented directly, it is likely that multiple incompatible schedulers will spring up in user code, greatly impeding a later unification.


The new command:

yieldto cmd ?arg1...?

shall accept one or more arguments:

cmd - The name of a command to invoke in place of the current coroutine invocation.

arg1... - The arguments to pass to the given command.

It shall have the following effects:

  1. The cmd argument shall be resolved in the current coroutine's context, resulting in a command to invoke. If resolution fails, the error is presented in the coroutine's context.

  2. The current coroutine shall suspend its execution in the same way as with the yield command.

  3. The command that invokes the coroutine shall be placed into a state such that it will accept multiple arguments when it is next invoked, rather than the single argument demanded by yield.

  4. The command and arguments shall be invoked in just the same way as if they had been called directly from the coroutine's caller. The given command replaces the coroutine invocation on the runtime stack. Data and status returned from the given command are returned to the context that invoked the coroutine.

  5. When the coroutine is resumed, any arguments passed into the coroutine command are assembled into a list and returned as the value of the yieldto command.

In other words, yieldto means "suspend the current coroutine and tailcall the given command: yieldto is to yield as tailcall is to return." In addition, yieldto causes the current coroutine to accept multiple arguments on its next invocation.

Relationship with the Earlier Proposals

TIP #372 proposes a yieldm command that allows a coroutine to yield and subsequently accept multiple arguments when resumed. The requested functionality of TIP #372 can be layered trivially atop this proposal: a one-line implementation of the yieldm command would be:

interp alias {} yieldm {} yieldto return -level 0

TIP #373 proposed yieldto together with a separate yieldset command. The latter allowed a coroutine to designate a set of arguments and defaults. The advantage over simply passing the arguments as a list was that error messages for incorrect numbers of arguments could be generated automatically, and that info args and info body could introspect into the desired argument list. Since the error message generation can be done readily by auxiliary procedures, and the introspection is something of a nicety, this proposal defers the implementation of yieldset.

TIP #375, which replaced TIP #373, proposed a yieldto command that is the same as the current proposal's, except that it could transmit only a single argument when the corouti