Categories
Posts in this category
- Introduction
- Strings, Arrays, Hashes;
- Types
- Basic Control Structures
- Subroutines and Signatures
- Objects and Classes
- Contexts
- Regexes (also called "rules")
- Junctions
- Comparing and Matching
- Containers and Values
- Where we are now - an update
- Changes to Perl 5 Operators
- Laziness
- Custom Operators
- The MAIN sub
- Twigils
- Enums
- Unicode
- Scoping
- Regexes strike back
- A grammar for (pseudo) XML
- Subset Types
- The State of the implementations
- Quoting and Parsing
- The Reduction Meta Operator
- The Cross Meta Operator
- Exceptions and control exceptions
- Common Perl 6 data processing idioms
- Currying
Thu, 09 Jul 2009
Exceptions and control exceptions
Permanent link
NAME
"Perl 5 to 6" Lesson 26 - Exceptions and control exceptions
SYNOPSIS
try { die "OH NOEZ"; CATCH { say "there was an error: $!"; } }
DESCRIPTION
Exceptions are, contrary to their name, nothing exceptional. In fact they are part of the normal control flow of programs in Perl 6.
Exceptions are generated either by implicit errors (for example calling a non-existing method, or type check failures) or by explicitly calling die
or other functions.
When an exception is thrown, the program searches for CATCH
statements or try
blocks in the caller frames, unwinding the stack all the way (that means it forcibly returns from all routines called so far). If no CATCH
or try
is found, the program terminates, and prints out a hopefully helpful error message. If one was found, the error message is stored in the special variable $!
, and the CATCH
block is executed (or in the case of a try
without a CATCH block the try block returns Any
).
So far exceptions might still sound exceptional, but error handling is integral part of each non-trivial application. But even more, normal return
statements also throw exceptions!
They are called control exceptions, and can be caught with CONTROL
blocks, or are implicitly caught at each routine declaration.
Consider this example:
use v6; sub s { my $block = -> { return "block"; say "still here" }; $block(); return "sub"; } say s(); # block
Here the return "block"
throws a control exception, causing it to not only exit the current block (and thus not printing still here
on the screen), but also exiting the subroutine, where it is caught by the sub s...
declaration. The payload, here a string, is handed back as the return value, and the say
in the last line prints it to the screen.
Adding a CONTROL { ... }
block to the scope in which $block
is called causes it to catch the control exception.
Contrary to what other programming languages do, the CATCH
/CONTROL
blocks are within the scope in which the error is caught (not on the outside), giving it full access to the lexical variables, which makes it easier to generate useful error message, and also prevents DESTROY blocks from being run before the error is handled.
Unthrown exceptions
Perl 6 embraces the idea of multi threading, and in particular automated parallelization. To make sure that not all threads suffer from the termination of a single thread, a kind of "soft" exception was invented.
When a function calls fail($obj)
, it returns a special value of undef
, which contains the payload $obj
(usually an error message) and the back trace (file name and line number). Processing that special undefined value without check if it's undefined causes a normal exception to be thrown.
my @files = </etc/passwd /etc/shadow nonexisting>; my @handles = hyper map { open($_) }, @files; # hyper not yet implement
In this example the hyper
operator tells map
to parallelize its actions as far as possible. When the opening of the nonexisting
file fails, an ordinary die "No such file or directory"
would also abort the execution of all other open
operations. But since a failed open calls fail("No such file or directory"
instead, it gives the caller the possibility to check the contents of @handles
, and it still has access to the full error message.
If you don't like soft exceptions, you say use fatal;
at the start of the program and cause all exceptions from fail()
to be thrown immediately.
MOTIVATION
A good programming language needs exceptions to handle error conditions. Always checking return values for success is a plague and easily forgotten.
Since traditional exceptions can be poisonous for implicit parallelism, we needed a solution that combined the best of both worlds: not killing everything at once, and still not losing any information.