BrowserREPL-button-tip-on BrowserREPL-button-tip-off

EditButtonTip 2026-04-19

Control flow

Statements used to control the flow of execution

Statements§

Raku programs consist of one or more statements. Simple statements are separated by semicolons. The following program will print "Hello" and then "World" on the next line.

say "Hello";
say "World";
Code

In most places where spaces appear in a statement, and before the semicolon, they may be split up over many lines. Also, multiple statements may appear on the same line. It would be awkward, but the above example could also be written as:

say
"Hello"; say "World";
Code

Blocks§

Like many other languages, Raku uses blocks enclosed by { and } to turn a sequence of statements into a Block that acts as a single one. It is OK to omit the semicolon between the last statement in a block and the closing }.

{ say "Hello"; say "World" }
Code

When a block stands alone as a statement, it will be entered immediately after the previous statement finishes, and the statements inside it will be executed.

say 1;                    # OUTPUT: «1␤»
{ say 2; say 3 };         # OUTPUT: «2␤3␤»
say 4;                    # OUTPUT: «4␤»
Code

Unless it stands alone as a statement, a block simply creates a closure. The statements inside are not executed immediately. Closures are another topic and how they are used is explained elsewhere. For now it is just important to understand when blocks run and when they do not:

say "We get here";
{ say "then here." };
{ say "not here"; 0; } or die;
Code

In the above example, after running the first statement, the first block stands alone as a second statement, so we run the statement inside it. The second block is a closure, so instead, it makes an object of type Block but does not run it. Object instances are usually considered to be true, so the code does not die, even though that block would evaluate to 0, were it to be executed. The example does not say what to do with the Block object, so it just gets thrown away.

Most of the flow control constructs covered below are just ways to tell Raku when, how, and how many times, to enter blocks like that second block.

Before we go into those, an important side-note on syntax: If there is nothing (or nothing but comments) on a line after a closing curly brace where you would normally put semicolon, then you do not need the semicolon:

# All three of these lines can appear as a group, as is, in a program
{ 42.say }                # OUTPUT: «42␤»
{ 43.say }                # OUTPUT: «43␤»
{ 42.say }; { 43.say }    # OUTPUT: «42␤43␤»
Code

...but:

{ 42.say }  { 43.say }    # Syntax error
{ 42.say; } { 43.say }    # Also a syntax error, of course
Code

So, be careful when you backspace in a line-wrapping editor:

{ "Without semicolons line-wrapping can be a bit treacherous.".say } \
{ 43.say } # Syntax error
Code

You have to watch out for this in most languages anyway to prevent things from getting accidentally commented out. Many of the examples below may have unnecessary semicolons for clarity.

Class bodies behave like simple blocks for any top level expression; same goes to roles and other packages, like grammars (which are actually classes) or modules.

class C {
    say "I live";
    die "I will never live!"
};
my $c = C.new;                              │
# OUTPUT: Fails and writes «I live␤I will never live!␤
Code

This block will first run the first statement, and then die printing the second statement. $c will never get a value.

Phasers§

Blocks may have phasers: special labeled blocks that break their execution into phases that run in particular phases. See the page phasers for the details.

do§

The simplest way to run a block where it cannot be a stand-alone statement is by writing do before it:

# This dies half of the time
do { say "Heads I win, tails I die."; Bool.pick } or die; say "I win.";
Code

Note that you need a space between the do and the block.

The whole do {...} evaluates to the final value of the block. The block will be run when that value is needed in order to evaluate the rest of the expression. So:

False and do { 42.say };
Code

...will not say 42. However, the block is only evaluated once each time the expression it is contained in is evaluated:

# This says "(..1 ..2 ..3)" not "(..1 ...2 ....3)"
my $f = "."; say do { $f ~= "." } X~ 1, 2, 3;
Code

In other words, it follows the same reification rules as everything else.

Technically, do is a loop which runs exactly one iteration.

A do may also be used on a bare statement (without curly braces) but this is mainly just useful for avoiding the syntactical need to parenthesize a statement if it is the last thing in an expression:

3, do if 1 { 2 }  ; # OUTPUT: «(3, 2)␤»
3,   (if 1 { 2 }) ; # OUTPUT: «(3, 2)␤»
Code
3,    if 1 { 2 }  ; # Syntax error
Code

As a consequence, do does not run blocks that, by their syntax, must be functions. For example, if -> is used to specify a signature, do treats these as single-expression statements.

Thus, adding -> to our first example prevents the closure from being evaluated:

# This never dies and never prints "Heads I win, tails I die."
do -> { say "Heads I win, tails I die."; Bool.pick } or die; say "I win.";
Code

start§

The simplest way to run a statement or block asynchronously is by writing start before it:

start { sleep 1; say "done" }
say "working";
# working, done
Code

Note that you need a space between the start and the block. In the example above, the start block is in sink context since it's not assigned to a variable. From version 6.d, these sunk blocks have an exception handler attached:

start { die "We're dead"; }
say "working";
sleep 10;
Code

This code will print Unhandled exception in code scheduled on thread 4 We're dead in version 6.d, while it will simply get out after waiting for 10 seconds in version 6.c.

The start {...} immediately returns a Promise that can be safely ignored if you are not interested in the result of the block. If you are interested in the final value of the block, you can call the .result method on the returned promise. So:

my $promise = start { sleep 10; 42 }
# ... do other stuff
say "The result is $promise.result()";
Code

If the code inside the block has not finished, the call to .result will wait until it is done.

A start used on a bare statement is useful when the only thing to do asynchronously is a subroutine or method:

sub get42 { 42 }
my $promise = start get42;
say $promise.result; # OUTPUT: «42␤»
Code

Note that start code does not have access to the special variables $! and $/ of its outer block, but receives new ones, so every asynchronous task has its per-task state.

Thus, try expressions and regex matches executed in the asynchronous task have their per-task state.

'a' ~~ /a/; # $/ is set to 「a」
try die;    # $! is defined now with an anonymous AdHoc exception
# as a code block
await start { say $! }; # OUTPUT: «Nil␤»
await start { say $/ }; # OUTPUT: «Nil␤»
# as a single statement
await start $!.say;     # OUTPUT: «Nil␤»
await start $/.say;     # OUTPUT: «Nil␤»
Code

if§

To conditionally run a block of code, use an if followed by a condition. The condition, an expression, will be evaluated immediately after the statement before the if finishes. The block attached to the condition will only be evaluated if the condition means True when coerced to Bool. Unlike some languages the condition does not have to be parenthesized, instead the { and } around the block are mandatory:

if 1 { "1 is true".say }  ; # says "1 is true"
Code
if 1   "1 is true".say    ; # syntax error, missing block
Code
if 0 { "0 is true".say }  ; # does not say anything, because 0 is false
Code
if 42.say and 0 { 43.say }; # says "42" but does not say "43"
Code

There is also a form of if called a "statement modifier" form. In this case, the if and the condition come after the code you want to run conditionally. Do note that the condition is still always evaluated first:

43.say if 42.say and 0;     # says "42" but does not say "43"
43.say if 42.say and 1;     # says "42" and then says "43"
say "It is easier to read code when 'if's are kept on left of screen"
    if True;                # says the above, because it is true
{ 43.say } if True;         # says "43" as well
Code

The statement modifier form is probably best used sparingly.

The if statement itself will either Slip us an empty list, if it does not run the block, or it will return the value which the block produces:

my $d = 0; say (1, (if 0 { $d += 42; 2; }), 3, $d); # says "(1 3 0)"
my $c = 0; say (1, (if 1 { $c += 42; 2; }), 3, $c); # says "(1 2 3 42)"
say (1, (if 1 { 2, 2 }), 3);         # does not slip, says "(1 (2 2) 3)"
Code

For the statement modifier it is the same, except you have the value of the statement instead of a block:

say (1, (42 if True) , 2); # says "(1 42 2)"
say (1, (42 if False), 2); # says "(1 2)"
say (1,  42 if False , 2); # says "(1 42)" because "if False, 2" is true
Code

The if does not change the topic ($_) by default. In order to access the value which the conditional expression produced, you have to ask for it more strongly:

$_ = 1; if 42 { $_.say }                ; # says "1"
$_ = 1; if 42 -> $_ { $_.say }          ; # says "42"
$_ = 1; if 42 -> $a { $_.say;  $a.say } ; # says "1" then says "42"
$_ = 1; if 42       { $_.say; $^a.say } ; # says "1" then says "42"
Code

This is especially useful for patterns of the kind "if something does not evaluate to False, do something with it":

sub get-user-id($username) { #`(return 0 if no such username exists) }

if prompt 'Enter username: ' -> $username {
    if get-user-id($username) -> $user-id {
        say "Found id $user-id for name $username";
    }
}
Code

Here $username and $user-id are only defined inside their respective if block that guarantees their being True. This gives this solution an advantage over the more conventional my $username = …; if $username {…}.

Compare with, which tests for definedness rather than truth, and topicalizes by default. (The second if in the above example could be replaced by with if the routine get-user-id returned Nil rather than 0 for nonexistent usernames.)

else/elsif§

A compound conditional may be produced by following an if conditional with else to provide an alternative block to run when the conditional expression is false:

if 0 { say "no" } else { say "yes" }   ; # says "yes"
if 0 { say "no" } else{ say "yes" }    ; # says "yes", space is not required
Code

The else cannot be separated from the conditional statement by a semicolon, but as a special case, it is OK to have a newline.

if 0 { say "no" }; else { say "yes" }  ; # syntax error
Code
if 0 { say "no" }
else { say "yes" }                     ; # says "yes"
Code

Additional conditions may be sandwiched between the if and the else using elsif. An extra condition will only be evaluated if all the conditions before it were false, and only the block next to the first true condition will be run. You can end with an elsif instead of an else if you want.

if 0 { say "no" } elsif False { say "NO" } else { say "yes" } # says "yes"
if 0 { say "no" } elsif True { say "YES" } else { say "yes" } # says "YES"

if 0 { say "no" } elsif False { say "NO" } # does not say anything

sub right { "Right!".say; True }
sub wrong { "Wrong!".say; False }
if wrong() { say "no" } elsif right() { say "yes" } else { say "maybe" }
# The above says "Wrong!" then says "Right!" then says "yes"
Code

You cannot use the statement modifier form with else or elsif:

42.say if 0 else { 43.say }            # syntax error
Code

All the same rules for semicolons and newlines apply, consistently

if 0 { say 0 }; elsif 1 { say 1 }  else { say "how?" } ; # syntax error
if 0 { say 0 }  elsif 1 { say 1 }; else { say "how?" } ; # syntax error
Code
if 0 { say 0 }  elsif 1 { say 1 }  else { say "how?" } ; # says "1"
Code
if 0 { say 0 } elsif 1 { say 1 }
else { say "how?" }                                    ; # says "1"

if 0 { say 0 }
elsif 1 { say 1 } else { say "how?" }                  ; # says "1"

if        0 { say "no" }
elsif False { say "NO" }
else        { say "yes" }                              ; # says "yes"
Code

The whole thing either Slips us an empty list (if no blocks were run) or returns the value produced by the block that did run:

my $d = 0; say (1,
                (if 0 { $d += 42; "two"; } elsif False { $d += 43; 2; }),
                3, $d); # says "(1 3 0)"
my $c = 0; say (1,
                (if 0 { $c += 42; "two"; } else { $c += 43; 2; }),
                3, $c); # says "(1 2 3 43)"
Code

It's possible to obtain the value of the previous expression inside an else, which could be from if or the last elsif if any are present:

$_ = 1; if 0     { } else -> $a { "$_ $a".say } ; # says "1 0"
$_ = 1; if False { } else -> $a { "$_ $a".say } ; # says "1 False"

if False { } elsif 0 { } else -> $a { $a.say }  ; # says "0"
Code

unless§

When you get sick of typing "if not (X)" you may use unless to invert the sense of a conditional statement. You cannot use else or elsif with unless because that ends up getting confusing. Other than those two differences unless works the same as if:

unless 1 { "1 is false".say }  ; # does not say anything, since 1 is true
Code
unless 1   "1 is false".say    ; # syntax error, missing block
Code
unless 0 { "0 is false".say }  ; # says "0 is false"
Code
unless 42.say and 1 { 43.say } ; # says "42" but does not say "43"
43.say unless 42.say and 0;      # says "42" and then says "43"
43.say unless 42.say and 1;      # says "42" but does not say "43"

$_ = 1; unless 0 { $_.say }           ; # says "1"
$_ = 1; unless 0 -> $_ { $_.say }     ; # says "0"
$_ = 1; unless False -> $a { $a.say } ; # says "False"

my $c = 0; say (1, (unless 0 { $c += 42; 2; }), 3, $c); # says "(1 2 3 42)"
my $d = 0; say (1, (unless 1 { $d += 42; 2; }), 3, $d); # says "(1 3 0)"
Code

with orwith without§

The with statement is like if, but tests for definedness rather than truth, and it topicalizes on the condition, much like given:

with "abc".index("a") { .say }      # prints 0
Code

Similarly to elsif, orwith may be used to chain definedness tests:

# The below code says "Found 'a' at 0"
my $s = "abc";
with   $s.index("a") { say "Found 'a' at $_" }
orwith $s.index("b") { say "Found 'b' at $_" }
orwith $s.index("c") { say "Found 'c' at $_" }
else                 { say "Didn't find 'a', 'b' or 'c'" }
Code

You may intermix if-based and with-based clauses.

# This says "Yes"
if 0 { say "No" } orwith Nil { say "No" } orwith 0 { say "Yes" };
Code

As with unless, you may use without to check for undefinedness, but you may not add an else clause:

my $answer = Any;
without $answer { warn "Got: {$_.raku}" }
Code

There are also with and without statement modifiers:

my $answer = (Any, True).roll;
say 42 with $answer;
warn "undefined answer" without $answer;
Code

As with the other chainable constructs, an else completing a with/if..orwith/elsif chain will itself topicalize to the value of the prior (failed) condition's topic (either the topic of with or the final orwith or elsif).

In the case of an else following a with or orwith, topicalizing a value guaranteed to be undefined may seem useless. But it makes for a useful idiom when used in conjunction with operations that may fail, because Failure values are always undefined:

sub may_fail( --> Numeric:D ) {
  my $value = (^10).pick || fail "Zero is unacceptable";
  fail "Odd is also not okay" if $value % 2;
  return $value;
}

with may_fail() -> $value { # defined, so didn't fail
  say "I know $value isn't zero or odd."
} else { # undefined, so failed, and the Failure is the topic
  say "Uh-oh: {.exception.message}."
}
Code

Note that while topicalizing a Failure marks it handled—so you can use the with/else to proceed safely with execution—it doesn't make the Failure value itself safe. Even within the else clause, if you try to use the value directly, it will result in your else clause itself failing (or, in Rakudo, "promoting" the Failure into a thrown exception).

But as seen above, you can use the methods of a handled Failure object the else topicalizes, such as exception, if you wish to provide diagnostics or interrogate the underlying Exception.

when§

The when block is similar to an if block and either or both can be used in an outer block; they also both have a "statement modifier" form. But there is a difference in how following code in the same, outer block is handled: When the when block is executed, control is passed to the enclosing block and following statements are ignored; but when the if block is executed, following statements are executed. [ 1 ] The following examples should illustrate the if or when block's default behavior assuming no special exit or other side effect statements are included in the if or when blocks:

{
    if X {...} # if X is true in Boolean context, block is executed
    # following statements are executed regardless
}
{
    when X {...} # if X is true in Boolean context, block is executed
                 # and control passes to the outer block
    # following statements are NOT executed
}
Code

Should the if and when blocks above appear at file scope, following statements would be executed in each case.

There is one other feature when has that if doesn't: the when's Boolean context test defaults to $_ ~~ while the if's does not. That has an effect on how one uses the X in the when block without a value for $_ (it's Any in that case and Any smartmatches on True: Any ~~ True yields True). Consider the following:

{
    my $a = 1;
    my $b = True;
    when $a    { say 'a' }; # no output
    when so $a { say 'a' }  # a ("so $a" 'so' coerces $a to Boolean context True
                            # which matches with Any)
    when $b    { say 'b' }; # no output (this statement won't be run)
}
Code

Finally, when's statement modifier form does not affect execution of following statements either inside or outside of another block:

say "foo" when X; # if X is true statement is executed
                  # following statements are not affected
Code

Since a successful match will exit the block, the behavior of this piece of code:

$_ = True;
my $a;
{
    $a = do when .so { "foo" }
};
say $a; # OUTPUT: «(Any)␤»
Code

is explained since the do block is abandoned before any value is stored or processed. However, in this case:

$_ = False;
my $a;
{
    $a = do when .so { "foo" }
};
say $a; # OUTPUT: «False␤»
Code

the block is not abandoned since the comparison is false, so $a will actually get a value.

for§

The for loop iterates over a list, running the statements inside a Block once on each iteration. If the block takes parameters, the elements of the list are provided as arguments. By default, the block takes one parameter, $_:

my @foo = 1..3;
for @foo { $_.print } # prints each value contained in @foo
for @foo { .print }   # same thing, because .print implies a $_ argument
for @foo { 42.print } # prints 42 as many times as @foo has elements
Code

Pointy block syntax or a placeholder may be used to name the parameter:

my @foo = 1..3;
for @foo -> $item { print $item }
for @foo { print $^item }            # same thing
Code

Multiple parameters can be declared, in which case the iterator takes as many elements from the list as needed before running the block.

my @foo = 1..3;
for @foo.kv -> $idx, $val { say "$idx: $val" }
my %hash = <a b c> Z=> 1,2,3;
for %hash.kv -> $key, $val { say "$key => $val" }
for 1, 1.1, 2, 2.1 { say "$^x < $^y" }  # OUTPUT: «1 < 1.1␤2 < 2.1␤»
Code

Parameters of a pointy block can have default values, allowing the code to handle lists with missing elements.

my @list = 1,2,3,4;
for @list -> $a, $b = 'N/A', $c = 'N/A' {
    say "$a $b $c"
}
# OUTPUT: «1 2 3␤4 N/A N/A␤»
Code

When no parameters are specified for a for loop's block, when can be used within it similarly to how it's used in a given block:

# A solution for FizzBuzz:
for 1..100 {
    when * %% 15 { say 'FizzBuzz' }
    when * %% 3  { say 'Fizz' }
    when * %% 5  { say 'Buzz' }
    default      { say $_ }
}
Code

If the postfix form of for is used, a block is not required and the topic is set for the statement list.

say „I $_ butterflies!“ for <♥ ♥ ♥>;
# OUTPUT: «I ♥ butterflies!␤I ♥ butterflies!␤I ♥ butterflies!␤»
Code

A for may be used on lazy lists – it will only take elements from the list when they are needed, so to read a file line by line, you could use:

for $*IN.lines -> $ln { $ln.say }
Code

Iteration variables are always lexical, so you don't need to use my to give them the appropriate scope. Also, they are read-only aliases. If you need them to be writable, use <-> instead of ->. Alternatively, you can add the is rw trait; this performs a binding operation so assigning to the parameter changes the value of the variable at the caller side. If instead you want to modify copies of the arguments within the block, add is copy.

my @foo = 1..3;
for @foo <-> $value {
    $value = $value %% 2 ?? "Even" !! "Odd"
}

say @foo; # OUTPUT: «[Odd Even Odd]␤»

@foo = 1..3;
for @foo -> $value is rw {
    $value = $value %% 2 ?? "Even" !! "Odd"
}

say @foo; # OUTPUT: «[Odd Even Odd]␤»

@foo = 1..3;
my @bar;
for @foo -> $value is copy {
    $value = $value %% 2 ?? "Even" !! "Odd";
    @bar.push: $value
}

say @foo; # OUTPUT: «[1 2 3]␤»
say @bar; # OUTPUT: «[Odd Even Odd]␤»
Code

This rule also applies to the topic variable $_, which by default is a read-write alias; it will become read-only if it's used in a -> loop.

my @foo = 1..3;
for @foo -> $_ { $_.say }

# Error: ...require mutable arguments
for @foo -> $_ { $_++ }
Code

A for loop can produce a List of the values produced by each run of the attached block. To capture these values, put the for loop in parenthesis or assign them to an array:

(for 1, 2, 3 { $_ * 2 }).say;              # OUTPUT: «(2 4 6)␤»
my @a = do for 1, 2, 3 { $_ * 2 }; @a.say; # OUTPUT: «[2 4 6]␤»
my @b = (for 1, 2, 3 { $_ * 2 }); @b.say;  # OUTPUT: «[2 4 6]␤»
Code

This implies that, if the results of the loop are not assigned, they will be in a sink context:

class Sunk {
    has $.titanic;
    method sink {
        say "Sinking $!titanic";
    }
}
Sunk.new( :titanic($_) ) for ^3;
for 1 {
    say "About to sink";
    Sunk.new( :titanic($_) );
}
# OUTPUT:
# Sinking 0
# Sinking 1
# Sinking 2
# About to sink
# Sinking 1
Code

The first loop creates three elements but they are in a sink context, so its sink method is called. In the second loop, its last statement will be in a sink context, so it will be also sunk (from version 6.d).

The Empty constant will act as a no-op for a loop:

say "Not here" for Empty;
Code

Will not do anything. This constant is equivalent to an empty Slip or List.

Undefined values will behave in the same way:

my @array := Empty;
.say for @array;
say @array; # OUTPUT: «()␤»
Code

Assigning Empty will effectively undefine an Array, using for over an undefined array will not even enter the loop, as shown, effectively behaving in the same way as above when Empty was used directly.

With hyper and race, the for loop is potentially iterated in parallel. See also the documentation for hyper and race in class Map.

my $primes_h = hyper for ^10_000 -> $number { $number if $number.is-prime };
say $primes_h.elems;   # OUTPUT: «1229␤»
say $primes_h.tail: 5; # OUTPUT: «(9931 9941 9949 9967 9973)␤»
Code

with hyper the order of elements is preserved.

my $primes_r = race for ^10_000 -> $number { $number if $number.is-prime };
say $primes_r.elems; # OUTPUT: «1229␤»
Code

Unlike hyper, race does not preserve the order of elements.

gather/take§

gather is a statement or block prefix that returns a sequence of values. The values come from calls to take in the dynamic scope of the gather code. In the following example, we implement a subroutine to compute the factors of an integer with gather (note that the factors are not generated in order):

sub factors( Int:D \n ) {
    my $k = 1;
    gather {
        while $k**2 < n {
            if n %% $k {
                take $k;
                take n div $k;
            }
            $k++;
        }
        take $k if $k**2 == n;
    }
}

say factors(36); # OUTPUT: «1, 36, 2, 18, 3, 12, 4, 9, 6␤»
Code

The gather/take combination can generate values lazily, depending on context. Binding to a scalar or sigilless container will force laziness. If you want to force lazy evaluation use the lazy subroutine or method. For example:

my @vals = lazy gather {
    take 1;
    say "Produced a value";
    take 2;
}
say @vals[0];
say 'between consumption of two values';
say @vals[1];

# OUTPUT:
# 1
# between consumption of two values
# Produced a value
# 2
Code

gather/take is scoped dynamically, so you can call take from subs or methods that are called from within gather:

sub weird(@elems, :$direction = 'forward') {
    my %direction = (
        forward  => sub { take $_ for @elems },
        backward => sub { take $_ for @elems.reverse },
        random   => sub { take $_ for @elems.pick(*) },
    );
    return gather %direction{$direction}();
}

say weird(<a b c>, :direction<backward> );          # OUTPUT: «(c b a)␤»
Code

If values need to be mutable on the caller side, use take-rw.

Note that the Seq created by gather/take may be coerced to another type. An example with assignment to a hash:

my %h = gather { take "foo" => 1; take "bar" => 2};
say %h;                   # OUTPUT: «{bar => 2, foo => 1}␤»
Code

Note: gather/take must not be used to collect results from react/whenever. The whenever block is not run from the thread that runs the gather/react, but the thread that runs the emit. On this thread, there is no handler for the control exception thrown by take, causing it to error out.

supply/emit§

The keyword supply creates a Supply object which is an on-demand supply that you can tap. It pairs with emit, which can be used anywhere from within supply prefixed code.

Using the emit method or the emit routine passes the invocant to the enclosing supply:

my $supply = supply {
    .emit for "foo", 42, .5;
}
$supply.tap: {
    say "received {.^name} ($_)";
}

# OUTPUT:
# received Str (foo)
# received Int (42)
# received Rat (0.5)
Code

See also: tap and Supplier.

given§

The given statement is Raku's topicalizing keyword in a similar way that switch topicalizes in languages such as C. In other words, given sets $_ inside the following block. The keywords for individual cases are when and default. The usual idiom looks like this:

my $var = (Any, 21, any <answer lie>).pick;
given $var {
    when 21 { say $_ * 2 }
    when 'lie' { .say }
    default { say 'default' }
}
Code

The given statement is often used alone:

given 42 { .say; .Numeric; }
Code

This is a lot more understandable than:

{ .say; .Numeric; }(42)
Code

default and when§

A block containing a default statement will be left immediately when the sub-block after the default statement is left. It is as though the rest of the statements in the block were skipped.

given 42 {
    "This says".say;
    $_ == 42 and ( default { "This says, too".say; 43; } );
    "This never says".say;
}
# The above block evaluates to 43
Code

A when statement will also do this (but a when statement modifier will not.)

In addition, when statements smartmatch the topic ($_) against a supplied expression such that it is possible to check against values, regular expressions, and types when specifying a match.

for 42, 43, "foo", 44, "bar" {
    when Int { .say }
    when /:i ^Bar/ { .say }
    default  { say "Not an Int or a Bar" }
}
# OUTPUT: «42␤43␤Not an Int or a Bar␤44␤Bar␤»
Code

In this form, the given/when construct acts much like a set of if/elsif/else statements. Be careful with the order of the when statements. The following code says "Int" not 42.

given 42 {
    when Int { say "Int" }
    when 42  { say 42 }
    default  { say "huh?" }
}
# OUTPUT: «Int␤»
Code

When a when statement or default statement causes the outer block to return, nesting when or default blocks do not count as the outer block, so you can nest these statements and still be in the same "switch" just so long as you do not open a new block:

given 42 {
    when Int {
      when 42  { say 42 }
      say "Int"
    }
    default  { say "huh?" }
}
# OUTPUT: «42␤»
Code

when statements can smartmatch against Signatures.

proceed and succeed§

Both proceed and succeed are meant to be used only from inside when or default blocks.

The proceed statement will immediately leave the when or default block, skipping the rest of the statements, and resuming after the block. This prevents the when or default from exiting the outer block.

given * {
    default {
        proceed;
        "This never says".say
    }
}
"This says".say;
Code

This is most often used to enter multiple when blocks. proceed will resume matching after a successful match, like so:

given 42 {
    when Int   { say "Int"; proceed }
    when 42    { say 42 }
    when 40..* { say "greater than 40" }
    default    { say "huh?" }
}
# OUTPUT: «Int␤»
# OUTPUT: «42␤»
Code

Note that the when 40..* match didn't occur. For this to match such cases as well, one would need a proceed in the when 42 block.

This is not like a C switch statement, because the proceed does not merely enter the directly following block, it attempts to match the given value once more, consider this code:

given 42 {
    when Int { "Int".say; proceed }
    when 43  { 43.say }
    when 42  { 42.say }
    default  { "got change for an existential answer?".say }
}
# OUTPUT: «Int␤»
# OUTPUT: «42␤»
Code

...which matches the Int, skips 43 since the value doesn't match, matches 42 since this is the next positive match, but doesn't enter the default block since the when 42 block doesn't contain a proceed.

By contrast, the succeed keyword short-circuits execution and exits the entire given block at that point. It may also take an argument to specify a final value for the block.

say do given 42 {
    when Int {
        succeed "Found";
        say "never this!";
    }
    when 42 { say 42 }
    default { say "dunno?" }
}
# OUTPUT: «Found␤»
Code

If you are not inside a when or default block, it is an error to try to use proceed or succeed.Also remember, the when statement modifier form does not cause any blocks to be left, and any succeed or proceed in such a statement applies to the surrounding clause, if there is one:

given 42 {
    { say "This says" } when Int;
    "This says too".say;
    when * > 41 {
       { "And this says".say; proceed } when * > 41;
       "This never says".say;
    }
    "This also says".say;
}
# OUTPUT: «This says␤This says too␤And this says␤This also says␤»
Code

given as a statement§

given can follow a statement to set the topic in the statement it follows.

.say given "foo";
# OUTPUT: «foo␤»

printf "%s %02i.%02i.%i",
        <Mo Tu We Th Fr Sa Su>[.day-of-week - 1],
        .day,
        .month,
        .year
    given DateTime.now;
# OUTPUT: «Sa 03.06.2016»
Code

loop§

The loop statement takes three statements in parentheses separated by ; that take the roles of initializer, conditional and incrementer, respectively. The initializer is executed once before the conditional is first tested. In case the initializer involves a variable declaration, the variable is declared as a lexical variable in the loop's outer or containing scope so that it can be used in code following the loop statement. The conditional is executed before each iteration and coerced to Bool; if False the loop is stopped. The incrementer is executed after each iteration, and before the conditional is tested again.

loop (my $i = 0; $i < 10; $i++) {       # A typical loop
    say $i;
}

my @str = "However Long".comb;          # Our very own .chars routine:
loop (my $l = 0;;) {                    # Declare $l in outer scope
    last if !@str[$l++]                 # and count chars until we hit
}                                       # an undefined element (Any)
say "The string is {--$l} chars long.";
Code

The infinite loop does not require parentheses.

loop { say 'forever' }
Code

The loop statement may be used to produce values from the result of each run of the attached block if it appears in lists:

(loop ( my $i = 0; $i++ < 3;) { $i * 2 }).say;               # OUTPUT: «(2 4 6)␤»
my @a = (loop ( my $j = 0; $j++ < 3;) { $j * 2 }); @a.say; # OUTPUT: «[2 4 6]␤»
my @b = do loop ( my $k = 0; $k++ < 3;) { $k * 2 }; @b.say; # same thing
Code

Unlike a for loop, one should not rely on whether returned values are produced lazily. It would probably be best to use eager to guarantee that a loop whose return value may be used actually runs:

sub heads-in-a-row {
    (eager loop (; 2.rand < 1;) { "heads".say })
}
Code

while, until§

The while statement executes the block as long as its condition is true. So

my $x = 1;
while $x < 4 {
    print $x++;
}
print "\n";

# OUTPUT: «123␤»
Code

Similarly, the until statement executes the block as long as the expression is false.

my $x = 1;
until $x > 3 {
    print $x++;
}
print "\n";

# OUTPUT: «123␤»
Code

The condition for while or until can be parenthesized, but there must be a space between the keyword and the opening parenthesis of the condition.

Both while and until can be used as statement modifiers. E. g.

my $x = 42;
$x-- while $x > 12
Code

See next, last, and related below for ways to fine-tune loop control. Also see repeat/while and repeat/until for other loop syntax.

All these forms may produce a return value the same way loop does.

repeat/while, repeat/until§

Executes the block at least once and, if the condition allows, repeats that execution. This differs from while/until in that the condition is evaluated at the end of the loop, even if it appears at the front.

my $x = -42;
repeat {
    $x++;
} while $x < 5;
$x.say; # OUTPUT: «5␤»

repeat {
    $x++;
} while $x < 5;
$x.say; # OUTPUT: «6␤»

repeat while $x < 10 {
    $x++;
}
$x.say; # OUTPUT: «10␤»

repeat while $x < 10 {
    $x++;
}
$x.say; # OUTPUT: «11␤»

repeat {
    $x++;
} until $x >= 15;
$x.say; # OUTPUT: «15␤»

repeat {
    $x++;
} until $x >= 15;
$x.say; # OUTPUT: «16␤»

repeat until $x >= 20 {
    $x++;
}
$x.say; # OUTPUT: «20␤»

repeat until $x >= 20 {
    $x++;
}
$x.say; # OUTPUT: «21␤»
Code

All these forms may produce a return value the same way loop does.

once§

A block or statement prefixed with once will be executed exactly once, even if placed inside a loop or a recursive routine.

my $guard;
loop {
    once $guard = 3;
    last if $guard-- <= 0;
once { put 'once' };
print 'many'
} # OUTPUT: «once␤manymanymany»
Code

This works per "clone" of the containing code object, so:

({ once 42.say } xx 3).map: {$_(), $_()}; # says 42 thrice
Code

Note that this is not a thread-safe construct when the same clone of the same block is run by multiple threads. Also remember that methods only have one clone per class, not per object.

LABELs§

while, until, loop and for loops can all take a label, which can be used to identify them for next, last, and redo. Nested loops are supported, for instance:

OUTAHERE: while True  {
    for 1,2,3 -> $n {
        last OUTAHERE if $n == 2;
    }
}
Code

Labels can be used also within nested loops to name each loop, for instance:

OUTAHERE:
loop ( my $i = 1; True; $i++ ) {
  OUTFOR:
    for 1,2,3 -> $n {
      # exits the for loop before its natural end
      last OUTFOR if $n == 2;
  }

  # exits the infinite loop
  last OUTAHERE if $i >= 2;
}
Code

next§

The next command starts the next iteration of the loop. So the code

my @x = 1, 2, 3, 4, 5;
for @x -> $x {
    next if $x == 3;
    print $x;
}
Code

prints "1245".

You can also use next in a map: the above example then looks like:

my @x = 1, 2, 3, 4, 5;
print @x.map: -> $x {
    next if $x == 3;
    $x
}
Code

prints "1 2 4 5" because a space is added between entries of a Seq when it is stringified. Note that that print was not put inside the block of the map, as it generally considered bad practice to run a map for its side-effects (in this case, the print.

If the NEXT phaser is present, it runs before the next iteration:

my Int $i = 0;
while ($i < 10) {
  if ($i % 2 == 0) {
    next;
  }

  say "$i is odd.";

  NEXT {
    $i++;
  }
}
# OUTPUT: «1 is odd.␤3 is odd.␤5 is odd.␤7 is odd.␤9 is odd.␤»
Code

In version 6.e.PREVIEW (available as of the 2021.07 Rakudo compiler release), it is also possible to return a value with the next statement. This is particularly useful when using it in a map:

my @x = 1, 2, 3, 4, 5;
print @x.map: -> $x {
    next 42 if $x == 3;
    $x
}
Code

prints "1 2 42 4 5".

In a whenever block, next immediately exits the block for the current value:

react {
    whenever Supply.interval(1) {
        next if .is-prime;
        say $_;
        done if $_ == 4;
    }
}
Code

prints "0", "1" and "4" - integers from 0 to 4 with primes skipped.

*Since version 6.d, the next command in a loop that collects its last statement values returns Empty for the iterations they run on.*

last§

The last command immediately exits the loop in question.

my @x = 1, 2, 3, 4, 5;
for @x -> $x {
    last if $x == 3;
    print $x;
}
Code

prints "12".

You can also use last in a map: the above example then looks like:

my @x = 1, 2, 3, 4, 5;
print @x.map: -> $x {
    last if $x == 3;
    $x
}
Code

prints "1 2" because a space is added between entries of a Seq when it is stringified. Note that that print was not put inside the block of the map, as it generally considered bad practice to run a map for its side-effects (in this case, the print.

If the LAST phaser is present, it runs before exiting the loop:

my Int $i = 1;
while ($i < 10) {
  if ($i % 5 == 0) {
    last;
  }

  LAST {
    say "The last number was $i.";
  }
  NEXT {
    $i++;
  }
}
# OUTPUT: «The last number was 5.␤»
Code

Since version 6.d, the last command in a loop that collects its last statement values returns Empty for the iterations they run on.

In version 6.e.PREVIEW (available as of the 2021.07 Rakudo compiler release), it is also possible to return a value with the last statement. This is particularly useful when using it in a map:

my @x = 1, 2, 3, 4, 5;
print @x.map: -> $x {
    last 42 if $x == 3;
    $x
}
Code

print "1 2 42".

redo§

The redo command restarts the loop block without evaluating the conditional again.

for 1..5 -> $current-level {
    state $total-attempts = 0;
    $total-attempts++;
    print("Entering #$current-level. ");
    if $total-attempts %% 3 {
        redo;
    }
}
# OUTPUT: «Entering #1... Entering #2... Entering #3... Entering #3... Entering #4... Entering #5... Entering #5... »
Code

return§

The sub return will stop execution of a subroutine or method, run all relevant phasers and provide the given return value to the caller. The default return value is Nil. If a return type constraint is provided it will be checked unless the return value is Nil. If the type check fails the exception X::TypeCheck::Return is thrown. If it passes a control exception is raised and can be caught with CONTROL.

Any return in a block is tied to the first Routine in the outer lexical scope of that block, no matter how deeply nested. Please note that a return in the root of a package will fail at runtime. A return in a block that is evaluated lazily (e.g. inside map) may find the outer lexical routine gone by the time the block is executed. In almost any case last is the better alternative. Please check the functions documentation for more information on how return values are handled and produced.

return-rw§

The sub return will return values, not containers. Those are immutable and will lead to runtime errors when attempted to be mutated.

sub s(){ my $a = 41; return $a };
say ++s();
CATCH { default { say .^name, ': ', .Str } };
# OUTPUT: «X::Multi::NoMatch.new(dispatcher …
Code

To return a mutable container, use return-rw.

sub s(){ my $a = 41; return-rw $a };
say ++s();
# OUTPUT: «42␤»
Code

The same rules as for return regarding phasers and control exceptions apply.

fail§

Leaves the current routine and returns the provided Exception or Str wrapped inside a Failure, after all relevant phasers are executed. If the caller activated fatal exceptions via the pragma use fatal;, the exception is thrown instead of being returned as a Failure.

sub f { fail "WELP!" };
say f;
CATCH { default { say .^name, ': ', .Str } }
# OUTPUT: «X::AdHoc: WELP!␤»
Code

Footnotes

1 |^| There are other ways to modify their default behavior; they are discussed in other sections.