Wow, what a flood. The idea of keep the various degrees of code parallelism similar in form yet distinct in detail sounds good to me.
I would like to suggest a radically different mechanism, that there be operators: fork, tfork, and cfork to split off a process, thread, or coroutine respectively. (The first might be called pfork if we're willing to give up history for forward consistancy.) Each would return a reference to the original code flow unit, the child code flow unit, and an indication of which one you are or if there was an error. (This is much like the current fork, except that I'd like the child to be provided with the ID of the parent, as well as the parent being provided with the ID of the child.) Fork, of course, would result in totally separate process encapsulation (or something transparently equivalent as is done in Perl 5 on Windows, I believe, where they use threads to simulate fork). All variables are independent copies after the fork, system calls from one process should not block the other, etc. Switching execution from one process to the other is at the whim of the operating system and is not necessarily going to happen at perl operation boundaries. Data transfer must be done external (either an already open pipeline or through the file system or such). Tfork would result in separate threads. If the OS provides them, they would likely be used, otherwise the interpreter might have to simulate them. All "my" variables are independent copies after the tfork, but "our" variables are shared. Operations that access "our" variables must be managed by the interpreter so that no language level actions are seen as broken up into separate portions by an ill-timed process switch to another thread. Especially if OS threads are used, the interpreter may have to take special action to ensure that switches do not expose an "our" update that is partially complete. While pipelines might work (depends upon whether the OS is supporting threads) and file system communication would work, normally communication would be done through "our" variables. Cfork would result in separate coroutines. They would have separate call stacks, and a separate copy of the current stack frame, but otherwise all "my" amd "our" variables would be fully shared. Process switching only occurs under control of the process themselves, so no operation level protection must be done. I'll assume the cfork is defined to return to the parent. The auto forking coroutine that Damian described could be a syntactic sugar based on this mechanism (while not being the only way of getting coroutines) so that: cosub func { # func body ... yield # func body ... } is treated as a macro that gets turned into: { my $parent = 0; my $child = 0; sub func { unless $state { my ( $p, $c, $which ) = cfork; if( $which eq IS_PARENT ) { $child.next; return $child; } elsif( $which eq IS_CHILD ) { @_ -> sub { yield; # func body yield; # func body }; yield undef while 1; } } $child.next( @_ ); } } which takes care of the magic "first time starts the coroutine, subsequent times resume it from where it left off" semantic for this special case, without requiring that anything that is a coroutine has to have that magic behaviour. The "next" method would be code of the form: next( $dest, @stuff ) { resume( $dest, @stuff ); } But resume needs a bit of magic. I'll write as a special variable $CUR_COROUTINE which always contains that object for the currently executing coroutine (one has to be generated for the initial mainline, either when perl starts or the first time that a cfork occurs). Every coroutine object has an attribute caller. When resume is called, it updates the caller attribute of the coroutine that is being resumed with a reference to $CUR_COROUTINE. Within a coroutine, then, you can always determine the ID of the coroutine that last resumed you with $CUR_ROUTINE.caller. This means that the yield operator could be macro that expands to: # yield( stuff ) resume( $CUR_COROUINE.caller, stuff ) Providing resume as the underlying mechanism for next/yield allows for non subordinate coroutine flow, like a round robin if you use resume (which loses the advantage/restriction of yield in which the coroutine that is the target is implicitly that coroutine that called you last); while still providing the simpler subordinate viewpoint for the more common simple cases (like generators).