In Exceptions§

See primary documentation in context for Catching exceptions.

It's possible to handle exceptional circumstances by supplying a CATCH block:

CATCH {
    when X::IO { $*ERR.say: "some kind of IO exception was caught!" }
}
X::IO::DoesNotExist.new(:$path, :trying("frobnicate")).throw

# OUTPUT: «some kind of IO exception was caught!»

Here, we are saying that if any exception of type X::IO occurs, then the message some kind of IO exception was caught! will be sent to stderr, which is what $*ERR.say does, getting displayed on whatever constitutes the standard error device in that moment, which will probably be the console by default.

Note that the match target is a role. To allow user defined exceptions to match in the same manner, they must implement the given role. Just existing in the same namespace will make them look alike but won't match in a CATCH block.

A CATCH block places any exception thrown in its topic variable ($_), thus it's possible to catch and handle various categories of exceptions inside a when block. To handle all exceptions, use a default statement. This example prints out almost the same information as the normal backtrace printer. Note that the dot methods apply to $_, which holds the Exception within the CATCH block.

CATCH {
     default {
         $*ERR.say: .message;
         for .backtrace.reverse {
             next if .file.starts-with('SETTING::');
             next unless .subname;
             $*ERR.say: "  in block {.subname} at {.file} line {.line}";
         }
     }
}

While this is a very common pattern, it is not strictly necessary to use default or when in a CATCH block. This is done to prevent the control flow from reaching the end of the block where, unless the exception has been resumed, the exception will continue to be thrown. Allowing this can be used for logging purposes, for instance:

# In the outermost block of a script...
my IO::Handle:D $log = open sprintf('logs/%d-%d.txt', $*INIT-INSTANT, $*PID), :a;
CATCH { $log.printf: "[%d] Died with %s: %s$?NL", now, .^name, .message }
END   { $log.close }

The CATCH block semantics apply to the entire lexical scope in which it is defined, regardless of where it is defined inside that lexical scope. It is therefore advised to put any CATCH block at the start of the lexical scope to which they apply so that the casual reader of the code can immediately see that there is something special going on.

In Phasers§

See primary documentation in context for CATCH.

Runs when an exception is raised by the current block, before the LEAVE phase. Also see Catching exceptions.