Whatever whenever does
Jnthn answered the question why $*IN.lines
blocks in a react block. What isn’t explained is what whenever
actually does before it starts blocking.
react {
whenever $*IN.lines { .say }
}
Looking at the syntax of a whenever
block, we see that whenever
takes a variable immediatly followed by a block. The only place where a structure like that can be defined is Grammar.nqp.
rule statement_control:sym<whenever> {
<sym><.kok>
[
|| <?{
nqp::getcomp('perl6').language_version eq '6.c'
|| $*WHENEVER_COUNT >= 0
}>
|| <.typed_panic('X::Comp::WheneverOutOfScope')>
]
{ $*WHENEVER_COUNT++ }
<xblock($PBLOCK_REQUIRED_TOPIC)>
}
Here the grammar just checks a few things without actually generating any code. So we head to Actions.nqp.
method statement_control:sym<whenever>($/) {
my $xblock := $<xblock>.ast;
make QAST::Op.new(
:op<call>, :name<&WHENEVER>, :node($/),
$xblock[0], block_closure($xblock[1])
);
}
The whenever block is converted to a call to sub WHENEVER
which we find in Supply.pm6.
sub WHENEVER(Supply() $supply, &block) {
There we go. A whenever
block takes its first argument of any type and calles .Supply
on it, as long as Any
is a parent of that type. In the case of $*IN
that type will typically be whatever IO::Handle.lines returns.
Seq.new(self!LINES-ITERATOR($close))
To turn a Seq
into a Supply
Any.Supply
calls self.list.Supply
. Nowhere in this fairly long chain of method lookups (this can’t be fast) are there any threads to be found. If we want to fix this we need to sneak a Channel
into $*IN.lines
which does exactly that.
$*IN.^can('lines')[1].wrap(my method {
my $channel = Channel.new;
start {
for callsame() {
last if $channel.closed;
$channel.send($_)
}
LEAVE $channel.close unless $channel.closed;
}
$channel
});
Or if we want to be explicit:
use Concurrent::Channelify;
react {
whenever signal(SIGINT) {
say "Got signal";
exit;
}
whenever $*IN.lines⇒ {
say "got line";
}
}
We already use ⚛ to indicate atomic operations. Maybe using prefix:<∥> to indicate concurrency makes sense. Anyway, we went lucky once again that Rakudo is implemented (mostly) in Perl 6 so we can find out where we need to poke it whenever we want to change it.
-
June 3, 2019 at 17:182019.22 When steroids are a given | Weekly changes in and around Perl 6