TIP #373: IMPROVED YIELDING SUPPORT FOR COROUTINES ==================================================== Version: $Revision: 1.7 $ Author: Miguel Sofer State: Withdrawn Type: Project Tcl-Version: 8.6 Vote: Pending Created: Thursday, 12 August 2010 URL: https://tip.tcl-lang.org373.html Post-History: Obsoletes: TIP #372 Obsoleted-By: TIP #375 ------------------------------------------------------------------------- ABSTRACT ========== This TIP proposes two new commands that improve control over the yielding behaviour of coroutines. RATIONALE =========== The new command *yieldto* allows a coroutine to suspend its execution and tailcall into an arbitrary command. It provides support for symmetric coroutines, simply specifying that the new command be another coroutine's resume command. The new command *yieldset* specifies the number of arguments that the coroutine's resume command will accept. Note that *yieldset* obsoletes [TIP #372], in the sense that it provides a different way of satisfying the same needs. DETAILED RATIONALE FOR "YIELDTO" ---------------------------------- The current *yield* and proposed *yieldm* suspend a coroutine and return the control to the coroutine's caller: they implement asymmetric coroutines. It is well known that symmetric and asymmetric coroutines have equal power, in that each can be implemented on top of the other. In Tcl8.6 as of today, symmetric coroutines can be implemented by coding a scheduler, which may but doesn't have to use the event loop. The new command *yieldto* implements symmetric coroutines directly. The ability of *yieldto* to yield to an arbitrary command also provides new possibilities. For instance, it allows to return a non-ok code to the caller without terminating the coroutine: yieldto return -level 0 -code 1 ERROR PROPOSAL FOR "YIELDTO" ======================== The new command *yieldto* /cmd/ ?/arg1 .../? causes: 1. the currently executing coroutine to suspend its execution (yield), 2. the command built from the arguments to *yieldto*, as resolved in the coroutine's context, is run in the coroutine's caller scope, 3. from the point of view of the coroutine's caller, the return value and options of the new command is what the coroutine returned on yielding. In other words, *yieldto* implements "suspend yourself and *tailcall* the new command"; *yieldto* is to *yield* as *tailcall* is to *return*. IMPLEMENTATION OF "YIELDTO" ----------------------------- Simply rename the *::tcl::unsupported::yieldTo* into the global namespace while getting rid of the camelCase, and extend the *coroutine* documentation and test-suite to refer to the new command. RATIONALE AND PROPOSAL FOR "YIELDSET" ======================================= [TIP #372] justifies and requests a different interface to a coroutine's resume command, allowing for an arbitrary number of arguments that shall be returned to the coroutine's body in a list. In order to limit the number of additional commands (*yieldm* and also *yieldmto*), and increase the flexibility, it is proposed to add a command: *yieldset* ?/arglist/? that sets the acceptable arguments for the resume command. If *yieldset* is called with no arguments it returns the current list of arguments. If *yieldset* is called with a list argument, it specifies the arguments to the resume command in the manner of *proc*. The argument names shall only be used for the error message if the resume command is called with an invalid number of arguments. In this manner, current *yield* behaves as if yieldset {{arg {}}} had been called. This shall remain the default behaviour. If *yieldset* is called outside of a coroutine context, it sets the default behaviour for newly created coroutines. If it is called within a coroutine context it sets the behaviour for the current coroutine only. In order to obtain [TIP #372]'s *yieldm* behaviour for *yield*, it would be necessary to call: yieldset args either before creating the coroutine or else within the coroutine body. The default arglist shall be *{{arg {}}}*, so that the current *yield* is the default behaviour. The arglist value can be changed with *yieldset* at any time, and remains valid until changed again. CAVEAT ======== Some new proposals for better coroutine interfaces are being discussed, based on ensembles and providing additional functionality. I do not foresee the discussion to settle in the immediate future. The current TIP is not meant to preempt any such design, it just attempts to provide a limited improvement that is easy to implement immediately. COPYRIGHT =========== This document has been placed in the public domain. ------------------------------------------------------------------------- TIP AutoGenerator - written by Donal K. Fellows