In Control flow§

See primary documentation in context for 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 
}

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) 
}

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 

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)␤» 

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␤» 

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