The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

NAME

Try::Tiny::Except - a thin wrapper around Try::Tiny

SYNOPSIS

As early as possible (startup code):

use Try::Tiny::Except ();

In normal code:

use Try::Tiny;

Then set (or localize)

$Try::Tiny::Except::always_propagate=sub {
  /ALARM/;                     # or whatever
};

to have exceptions that contain ALARM propgate through every catch block. finally blocks are still called though.

DESCRIPTION

Try::Tiny works great in most situations. However, in sometimes you might want a certain exception being propagated always without the possibility to catch it in a catch block or to ignore it. For instance CGI::Compile or mod_perl's ModPerl::Registry try to execute perl scripts in a persistent interpreter. Hence, they have to prevent exit being called by the script. The usual way to achieve that is to turn it into a special exception. But then you have to inspect all the evals in the code to make them aware of that special exception. Provided your code does not use plain eval but Try::Tiny instead, this is where Try::Tiny::Except comes to rescue.

Try::Tiny::Except can be used in 2 slightly different modes. First, you can simply replace all use Try::Tiny by use Try::Tiny::Except. In that case the try, catch and finally functions provided by Try::Tiny::Except will be used. This is totally fine. To make sure both modules behave exactly the same, I have copied the test suite from Try::Tiny and replaced all occurrences of use Try::Tiny by use Try::Tiny::Except. The advantage of this usage is that it is obvious to the reader which module is used. But it requires code changes.

The other usage mode is to load Try::Tiny::Except as early as possible when the interpreter is started. It loads then Try::Tiny and overwrites the try function. Later in the code you can either use Try::Tiny or use Try::Tiny::Except. Anyway, you'll get the try function provided by use Try::Tiny::Except.

How to make an exception always propagate?

Let's use a real-life example, CGI::Compile. This module overwrites exit with something like this:

*CORE::GLOBAL::exit=sub {
  die ["EXIT\n", $_[0] || 0];
};

So, a script performing exit is actually throwing an exception and $@ becomes an array with 2 elements where the first element is the string "EXIT\n".

To prevent this exception from ever being catched by a catch block or ignored by a bare try block, set $Try::Tiny::Except::always_propagate like this:

$Try::Tiny::Except::always_propagate=sub {
    ref eq 'ARRAY' and
    @$_==2 and
    $_->[0] eq "EXIT\n";
};

Now compile and run a script:

my $code=CGI::Compile->new(return_exit_val=>1)->compile('/path/to/script.pl');
my $rc=$code->();

If script.pl looks like this:

use Try::Tiny;
try {exit 19};
12;

$rc will become 19 instead of 12.

EXPORT

try, catch and finally are exported by default and on demand.

SEE ALSO

Try::Tiny

AUTHOR

Torsten Förtsch <torsten.foertsch@gmx.net>

COPYRIGHT AND LICENSE

Copyright (C) 2014 by Torsten Förtsch

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.14.2 or, at your option, any later version of Perl 5 you may have available.