Liz and I had a SubEthaEdit session on coroutines today, with the brief notes merged to S17 (Liz is working on Englishify them at this moment).
Basically, a coroutine is an object that supports a.start
method
that initiates the lightweight thread behind it, and return a object that may
be manipulated like any other threads. If you call it like a nullary function,
it activates the thread until it hits yield
, in which case it
gives the control back to the caller. The return
inside the
thread will end itself immediately. Either way, if you attempt to call a
finished thread, an exception will be thrown.
Then we get the extra magic of calling a Coroutine objects like a Code
object. This will trigger &Coroutine::postcircumfix<( )>
, which will take care of calling.start
again after the thread has finished, and arrange it so the next call to the coroutine will resume the ongoing thread instead of starting a new one.
Finally, there is the question of calling an ongoing coroutine with parameters. I think rebinding the parameters makes sense (as you can inhibit it using is copy
or explicit { my $x
), but iblech's idea of having yield
returning the Arglist makes sense too. In any case this is userland code, so one can change the behaviour with a trait or a subclass of Coroutines.
On the PIL2 front, I looked at the three special forms (Assignment, Binding, Apply) and decided to unify them into method calls, so the user can override them all inside the same object model -- "Everything is an object."
The Apply form is easiest, as it's just method postcircumfix<( )>
that takes an Arglist and gives back an Arglist. See the new S03 for more about the cool things you can do with Arglists.
Assignment is also manageable under the container model. It will be method infix:<=>
on Array, Hash, Scalar objects. The List objects constructed with infix:<,>
will also respond to this method, to implement the ($a, $b, $c) = (1, 2, 3)
forms.
Binding almost feel like it should be a non-user-overridable special form,
except we remembered the permanently-semi-official idea of Siglist objects,
constructed with the:()
notation. It turns out that if we
specify binding as a method on the Siglist object, and that the compiler
desugars LHS
always as:(LHS).infix:<:=>(RHS)
, it will all Just Work. Under this
regime, 3
will still be a compile-time error, as:(3)
would make no sense -- the macro that turns sub (3)
{...}
into sub ($ where {$_ ~~ 3}) {...}
would not apply to
bare Siglist construction forms.
So, PIL2 is looking good with fewer nodes and tighter object integration now. Maybe we are not yet at io's zero keywords level, but it's getting dangerously close. Note that all of this is outside specced domain -- we'll need to work them back to Synopses and tests, and run them through p6l and @Larry.
Of course, to recover a respectible performance under this regime, we need to rely on optimizers, early binding, and/or type inference. But that's two milestones ahead, so let's get the dynamism part right first...
Comments