The docs state that "The simplest way to run a block where it cannot be a stand-alone statement is by writing do
before it" and provide the following example:
# This dies half of the time
do { say "Heads I win, tails I die."; Bool.pick } or die; say "I win.";
However, do
doesn't seem to cause all blocks to run. In particular, it doesn't seem to run blocks with a signature:
do -> $a = 42 { say "ran with $a"; 0 } or die; say 'done'; # OUTPUT: «done»
So would it be better to say that do
treats a block as an expression which sometimes causes it to be run? Or is Rakudo incorrect in its behavior here? Or is my understanding incorrect?
The do
keyword turns a statement into an expression.
my @b = do for @a { $_² if $_ %% 2 }
my $c = do if @b > 4 { +@b } else { 3 }
A bare block can either be a statement:
my $a = 1;
say $a;
{
my $a = 2;
say $a;
}
say $a;
or it can be an expression:
my $code = { … }
When you use do
with a bare block it acts as the statement form, but also returning the last value evaluated.
my $result = do { say 'hi'; 5 }
# hi
say $result;
# 5
A pointy block on the other hand is always an expression.
my $code = -> $ { … }
Even if you don't assign it anywhere
say 'a';
-> { say 'hi' }
do -> { say 'bye' }
say 'b';
# a
# b
It is pointless to use do
with something that is already an expression.
Note that the do
keyword in the compiler takes a blorst
(block or statement) instead of just a statement because it doesn't make much sense to turn the block into a statement just to undo that and turn it into an expression-like block so that it will return its last value.
Basically blorst
only ever captures a statement, but it captures the block type of statement directly to simplify the internals of the compiler.