Statement prefixes
Statement prefixes are written in front of a statement, and change their meaning, their output, or the moment they are going to be run. Since they have a specific behavior, they are also sometimes specific to some statement or group of statements.
lazy
|Syntax,lazy (statement prefix)
As a statement prefix, lazy
acts in front of any statement, including for
loops, saving the execution for when the variable they are assigned to is
actually needed.
my $incremented = 0;
my $var = lazy for <1 2 3 4> -> $d {
$incremented++
};
say $incremented; # OUTPUT: «0»
say eager $var; # OUTPUT: «(0 1 2 3)»
say $incremented; # OUTPUT: «4»
The $incremented
variable is only incremented, that is, the internal part of
the loop is only run when we eagerly evaluate the variable $var
that
contains the lazy loop. Eagerness can be applied on a variable in other ways,
such as calling the .eager
method on it.
my @array = lazy { (^3).map( *² ) };
say @array; # OUTPUT: «[...]»
say @array.eager; # OUTPUT: «[0 1 4]»
This prefix can also be used in front of gather to make the inner statements behave lazily; in general, any set of statements that returns a value will be made lazy using this.
eager
|Syntax,eager (statement prefix)
The eager
statement prefix will eagerly return the result of the statements
behind, throwing away laziness and returning the result.
my $result := eager gather { for 1..3 { say "Hey"; take $_² } };
say $result[0]; # OUTPUT: «HeyHeyHey1»
gather
is implicitly lazy when bound to a scalar.
However, with eager
as a statement prefix it will run all three iterations in
the loop, as shown by the printed "Hey", even if we are just requesting the
first one in a row.
hyper
|Syntax,hyper (statement prefix), race
|Syntax,race (statement prefix)
A for
loop will automatically serialize any HyperSeq or
RaceSeq used in it; on the other hand hyper
and race
use (maybe simultaneous) threads to run different iterations in a loop:
my @a = hyper for ^100_000 { .is-prime }
This code is around 3x faster than the bare for
. But there are a couple of
caveats here:
The operation inside the loop should take enough time for threading to make sense.
There should be no read or write access to the same data structure inside the loop. Let the loop produce a result, and assign it.
If there's an I/O operation inside the loop, there might be some contention so please avoid it.
Main difference between hyper
and race
is the ordering of results. Use
hyper
if you need the loop results to be produced in order, race
if you
don't care.
quietly
|Syntax,quietly (statement prefix)
As a prefix, quietly
suppresses all runtime warnings produced by the
block or statement it precedes.
sub marine() {};
quietly say ~&marine; # OUTPUT: «marine»
sub told-you { warn 'hey...' };
quietly { told-you; warn 'kaput!' };
warn 'Telling you now!'; # OUTPUT: «Telling you now! [...] »
Calling .Str on code produces a warning.
Preceding the code with quietly
will just produce the output without warning.
try
|Syntax,try (statement prefix)
If you use try
in front of a statement, it will contain the exception
produced in it and store it in the $!
variable, just like when it's used in
front of a block.
try [].pop;
say $!; # OUTPUT: «Cannot pop from an empty Array..»
do
|Syntax,do (statement prefix)
do
can be used as a statement prefix to disambiguate the statement they
precede; this is needed, for instance, if you want to assign the result of a
for
statement. A bare for
will fail, but this will work:
my $counter = 0;
my $result = do for ^5 { $counter++ };
say $counter; # OUTPUT: «5»
say $result; # OUTPUT: «(0 1 2 3 4)»
do
is equivalent, as in other cases, to surrounding a statement with a
parenthesis. It can be used as an alternative with a (possibly more)
straightforward syntax.
sink
|Syntax,sink (statement prefix)
As in the case of the routine, sink
will run the statement,
throwing away the result. Use it in case you want to run some statement for the
side effects it produces.
my $counter = 0;
my $result = sink for ^5 { $counter++ };
say $counter; # OUTPUT: «5»
say $result; # OUTPUT: «(Any)»
The sink
statement prefix will also convert Failures into exceptions:
sub find-the-number ( Int $n where $n < 10 ) {
if $n == 7 {
return True;
} else {
fail "Not that number" ;
}
}
for 1..^10 {
try {
sink find-the-number($_);
};
say "Found $_" unless $!;
}
In this case, we will know that the number has been found only when the
try
block is not catching an exception.
react
|Syntax,react (statement prefix)
react
can be used in concurrent programs to create blocks of code that run
whenever some event occurs. It works with blocks, and also as a
statement prefix.
my Channel $KXGA .= new;
for ^100 {
$KXGA.send( (100000..200000).pick );
}
my @sums = ( start react whenever $KXGA -> $number {
say "In thread ", $*THREAD.id;
say "→ ", (^$number).sum;
} ) for ^10;
start { sleep 10; $KXGA.close(); }
await @sums;
In this case react
prefixes whenever
, which makes a long sum with every
number read from a channel.