I wish to consider amending "[TIP] 328 Coroutines" [http://www.tcl.tk/cgi-bin/tct/tip/328.html], along these lines: Invocation of a [coroutine] should accept multiple arguments, those arguments should be returned to the coroutine's [yield] as a list of actual parameters. The current implementation forbids invoking a coroutine with more than one argument. I have found, in practice, that many of my coroutine invocations are naturally like other command invocations, and take multiple arguments. The case for providing multi-arg'd coroutines is: 1. coroutines should be able to emulate any command, not just any single-arg'd command [[generality]] 2. to implement single-arg's coroutines in multi-arg'd coroutines is trivial - nothing needs to be done. The converse (implementing multi-arg'd coroutines under [coroutine] is inefficient and difficult. [[increased expressive power]] 3. there is no sound reason that the invocation of a coroutine should not resemble that of any other command [[principle of minimal surprise]] For these reasons, the core should be modified to accept multiple actual parameters to a coroutine invocation, ::yield should be modified to resemble ::yield2 below, and a new interface ::yieldm should be created to return the actual parameter list as it's passed. The only arguments in favour of single-arg'd coroutine I've heard are: 1. extra cost in packing (at invocation) and unpacking (in [yield]) the actual parameters. Total cost is building a 1-element list and 1 [lindex], both in C. I consider this to be insignificant compared to the cost of passing more than one argument, which is the more usual case in my experience. 2. the potential that coroutine invocation might require options to control the invocation in ways simple command call doesn't. Examples, IIRC, were [[`$coro -terminate`]] which would be interpreted as an unconditional termination. I find this hypothetical need unconvincing, as it would be as easily served by other kinds of interface to the coroutine (much as [info] has been pressed into service to provide information about a coroutine, some other hypothetical command like [[corocontrol $coro]] could be used to control the coro. ** Demonstration of point 2 [[increased expressive power]] ** CASE 1: (counterfactual) Assume a [[Coroutine]] which generates a command taking multiple args, to implement [coroutine] as we have it implemented: [[Coroutine]] would require no wrapping or changes to function as [coroutine] does now. Only [yield] would have to change. To provide precisely the same functionality as [yield] currently does it is necessary to strip off a single layer of [list]: ====== proc ::yield2 {value} { return [lindex [::yield $value] 0] } ====== No other changes are necessary. More likely, one would define ::yield like that, and create a new ::yield-variant which returned the whole invocation arg list. CASE 2: [[Coroutine]] in [[[coroutine]]] - implementing multi-arg'd coroutines over singe-arg'd [coroutine] ====== proc Coroutine {name command args} { set ns [namespace qualifiers $name] if {$ns eq ""} { set ns [uplevel 1 {namespace current}] } set name [namespace tail $name] set coco [::coroutine ${ns}::_C$name $command {*}args] trace add command ${ns}::_C$name delete "rename ${ns}::name {}" proc ${ns}::$name {args} { set name [lindex [info level 0] 0] set ns [namespace qualifiers $name] if {$ns eq ""} { set ns [uplevel 1 {namespace current}] } set name [namespace tail $name] tailcall ${ns}::_C$name $args } } ====== The predominant cost in this is that of tracing intermediate commands to avoid leakage. Even if this were not the case, the cost of calling a proc to wrap the extra args is considerable. The only alternative is to wrap the args on *each* invocation. One can provide variable assignment by signature (or [Occam]-like protocol): ====== proc entrypoint {value args} { uplevel 1 lassign [::yield $value] {*}$args } ====== This is possible in current [coroutine] the same way, but requires the caller to form args into lists on each invocation. [MS] Notes that this would require that the invocation's arguments be a list of {name,value} pairs. This breaks the wanted analogy to [proc], where the assignment to variables is positional and not by name. It would be possible to mimic [proc] perfectly, but in that case scripting the current [coroutine] functionality becomes cumbersome. ---- [jmn] 2010-04-15 I totally agree. I was thoroughly dismayed by the single arg coroutine thing. It just seems to go against the grain of the 'Tcl way' - for no real advantage. If it was multi-arg'd it would present an interesting way to build some command alternatives along the lines of existing mechanisms such as 'interp alias'. Having to wrap it to achieve this is ugly enough to discourage this sort of innovation especially if the whole point of the innovation was to do so in a situation where dispatch performance matters. ---- [MS] An alternative is to provide a new command (coroutine2?) which creates multi-arg commands. In that case, [yield] can be modified in C to do the right thing depending on the nature of the enclosing coroutine. For some reason which I'm not clear about (paternity?), this would be my current preference. A second command would also make it easy to allow the actual arguments to be passed positionally, as in [proc]. Some syntax would be needed to allow the invocation to ALSO pass the internal result from [yield], if one is wanted. Maybe something like coroutine coro2Cmd ::apply {{x1 x2} {...}} 42 42 coro2Cmd -yieldResult foo 11 22 that would cause the coro to be created with x1=x2=42. When it is later resumed: x1 is set to 11, x2 is set to 22, and [yield] returns foo. If no option -yieldResult is specified [yield] returns {}. <>Development