Provided by: libsyntax-keyword-try-perl_0.11-1build1_amd64 

NAME
"Syntax::Keyword::Try" - a "try/catch/finally" syntax for perl
SYNOPSIS
use Syntax::Keyword::Try;
sub foo
{
try {
attempt_a_thing();
return "success";
}
catch {
warn "It failed - $@";
return "failure";
}
}
DESCRIPTION
This module provides a syntax plugin that implements exception-handling semantics in a form familiar to
users of other languages, being built on a block labeled with the "try" keyword, followed by at least one
of a "catch" or "finally" block.
As well as providing a handy syntax for this useful behaviour, this module also serves to contain a
number of code examples for how to implement parser plugins and manipulate optrees to provide new syntax
and behaviours for perl code.
KEYWORDS
try
try {
STATEMENTS...
}
...
A "try" statement provides the main body of code that will be invoked, and must be followed by either a
"catch" statement, a "finally" statement, or both.
Execution of the "try" statement itself begins from the block given to the statement and continues until
either it throws an exception, or completes successfully by reaching the end of the block. What will
happen next depends on the presence of a "catch" or "finally" statement immediately following it.
The body of a "try {}" block may contain a "return" expression. If executed, such an expression will
cause the entire containing function to return with the value provided. This is different from a plain
"eval {}" block, in which circumstance only the "eval" itself would return, not the entire function.
The body of a "try {}" block may contain loop control expressions ("redo", "next", "last") which will
have their usual effect on any loops that the "try {}" block is contained by.
The parsing rules for the set of statements (the "try" block and its associated "catch" and "finally")
are such that they are parsed as a self- contained statement. Because of this, there is no need to end
with a terminating semicolon.
Note (especially to users of Try::Tiny and similar) that the "try {}" block itself does not necessarily
stop exceptions thrown inside it from propagating outside. It is the presence of a later "catch {}" block
which causes this to happen. A "try" with only a "finally" and no "catch" will still propagate exceptions
up to callers as normal.
catch
...
catch {
STATEMENTS...
}
A "catch" statement provides a block of code to the preceding "try" statement that will be invoked in the
case that the main block of code throws an exception. The "catch" block can inspect the raised exception
by looking in $@ in the usual way.
Presence of this "catch" statement causes any exception thrown by the preceding "try" block to be non-
fatal to the surrounding code. If the "catch" block wishes to optionally handle some exceptions but not
others, it can re-raise it (or another exception) by calling "die" in the usual manner.
As with "try", the body of a "catch {}" block may also contain a "return" expression, which as before,
has its usual meaning, causing the entire containing function to return with the given value. The body
may also contain loop control expressions ("redo", "next" or "last") which also have their usual effect.
If a "catch" statement is not given, then any exceptions raised by the "try" block are raised to the
caller in the usual way.
finally
...
finally {
STATEMENTS...
}
A "finally" statement provides a block of code to the preceding "try" statement (or "try/catch" pair)
which is executed afterwards, both in the case of a normal execution or a thrown exception. This code
block may be used to provide whatever clean-up operations might be required by preceding code.
Because it is executed during a stack cleanup operation, a "finally {}" block may not cause the
containing function to return, or to alter the return value of it. It also cannot see the containing
function's @_ arguments array (though as it is block scoped within the function, it will continue to
share any normal lexical variables declared up until that point). It is protected from disturbing the
value of $@. If the "finally {}" block code throws an exception, this will be printed as a warning and
discarded, leaving $@ containing the original exception, if one existed.
VALUE SEMANTICS
Warning: the feature described in this section is experimental. This experiment may be stablised in a
later version, or may be altered or removed without further notice. It is present here for testing
and evaluation purposes.
Additionally, on perl versions 5.18 and later, it will produce a warning in the "experimental"
category.
The syntax provided by this module may be used as a value-yielding expression. Because this syntax is
new, experimental, and somewhat surprising, it must be specifically requested by name "try_value":
use Syntax::Keyword::Try qw( try try_value );
my $result = try do { ... } catch { ... };
Also, on Perl versions 5.24 and later:
my $result = try do { ... } finally { ... };
my $result = try do { ... } catch { ... } finally { ... };
Specifically, note that the expression must be spelled as "try do { ... }" so that the syntax is distinct
from that used by control-flow statements. The interposed "do" keyword reminds the reader, and instructs
the syntax parser, that this will be an expression, not a statement. It is not necessary to similarly
notate the "catch" or "finally" blocks.
In this case, the syntax behaves syntactically like an expression, and may appear anywhere a normal
expression is allowed. It follows similar semantics to the purely control-flow case; if the code in the
"try" block does not throw an exception, then the expression as a whole yields whatever value the "try"
expression did. If it fails, then the "catch" block is executed and the expression yields its resulting
value instead. A "finally" block, if present, will be evaluated for side-effects before the rest of the
expression returns.
Remember that, as in the control-flow case, the "return" keyword will cause the entire containing
function to return, not just the "try" block.
OTHER MODULES
There are already quite a number of modules on CPAN that provide a "try/catch"-like syntax for Perl.
• Try
• TryCatch
• Try::Tiny
• Syntax::Feature::Try
They are compared here, by feature:
True syntax plugin
Like Try and Syntax::Feature::Try, this module is implemented as a true syntax plugin, allowing it to
provide new parsing rules not available to simple functions. Most notably here it means that the
resulting combination does not need to end in a semicolon.
In comparison, Try::Tiny is plain perl and provides its functionality using regular perl functions; as
such its syntax requires the trailing semicolon.
TryCatch is a hybrid that uses Devel::Declare to parse the syntax tree.
@_ in a try or catch block
Because the "try" and "catch" block code is contained in a true block rather than an entire anonymous
subroutine, invoking it does not interfere with the @_ arguments array. Code inside these blocks can
interact with the containing function's array as before.
This feature is unique among these modules; none of the others listed have this ability.
"return" in a try or catch block
Like TryCatch and Syntax::Feature::Try, the "return" statement has its usual effect within a subroutine
containing syntax provided by this module. Namely, it causes the containing "sub" itself to return.
In comparison, using Try or Try::Tiny mean that a "return" statement will only exit from the "try" block.
"next"/"last"/"redo" in a try or catch block
The loop control keywords of "next", "last" and "redo" have their usual effect on dynamically contained
loops.
Syntax::Feature::Try documents that these do not work there. The other modules make no statement either
way.
Value Semantics
Like Try and Syntax::Feature::Try, the syntax provided by this module only works as a syntax-level
statement and not an expression when the experimental "try_value" feature described above has not been
enabled. You cannot assign from the result of a "try" block. Additionally, final-expression value
semantics do not work, so it cannot be contained by a "do" block to yield this value.
In comparison, the behaviour implemented by Try::Tiny can be used as a valued expression, such as
assigned to a variable or returned to the caller of its containing function. Such ability is provided by
this module if the experimental "try_value" feature is enabled, though it must be spelled differently as
"try do { ... }".
"try" without "catch"
Like Syntax::Feature::Try, the syntax provided by this module allows a "try" block to be followed by only
a "finally" block, with no "catch". In this case, exceptions thrown by code contained by the "try" are
not suppressed, instead they propagate as normal to callers. This matches the behaviour familiar to Java
or C++ programmers.
In comparison, the code provided by Try and Try::Tiny always suppress exception propagation even without
an actual "catch" block.
The TryCatch module does not allow a "try" block not followed by "catch".
Typed "catch"
Like Try and Try::Tiny, this module makes no attempt to perform any kind of typed dispatch to distinguish
kinds of exception caught by "catch" blocks.
TryCatch and Syntax::Feature::Try both attempt to provide a kind of typed dispatch where different
classes of exception are caught by different blocks of code, or propagated up entirely to callers.
The author considers the lack of such ability in this module to be a feature. That kind of dispatch on
type matching of a controlling expression is too useful a behaviour to be constrained to exception
catching. If the language is to provide such a facility, it should be more universally applicable as a
stand-alone independent ability.
WITH OTHER MODULES
Future::AsyncAwait
As of "Future::AsyncAwait" version 0.10 and Syntax::Keyword::Try version 0.07, cross-module integration
tests assert that basic "try/catch" blocks inside an "async sub" work correctly, including those that
attempt to "return" from inside "try".
use Future::AsyncAwait;
use Syntax::Keyword::Try;
async sub attempt
{
try {
await func();
return "success";
}
catch {
return "failed";
}
}
KNOWN BUGS
Thread-safety at load time cannot be assured before perl 5.16
On perl versions 5.16 and above this module is thread-safe.
On perl version 5.14 this module is thread-safe provided that it is "use"d before any additional threads
are created.
However, when using 5.14 there is a race condition if this module is loaded late in the program startup,
after additional threads have been created. This leads to the potential for it to be started up multiple
times concurrently, which creates data races when modifying internal structures and likely leads to a
segmentation fault, either during load or soon after when more code is compiled.
As a workaround, for any such program that creates multiple threads, loads additional code (such as
dynamically-discovered plugins), and has to run on 5.14, it should make sure to
use Syntax::Keyword::Try;
early on in startup, before it spins out any additional threads.
(See also <https://rt.cpan.org/Public/Bug/Display.html?id=123547>)
$@ is not local'ised by "try do" before perl 5.24
On perl versions 5.24 and above, or when using only control-flow statement syntax, $@ is always correctly
"local"ised.
However, when using the experimental value-yielding expression version "try do {...}" on perl versions
5.22 or older, the "local"isation of $@ does not correctly apply around the expression. After such an
expression, the value of $@ will leak out if a failure happened and the "catch" block was invoked,
overwriting any previous value that was visible there.
(See also <https://rt.cpan.org/Public/Bug/Display.html?id=124366>)
ACKNOWLEDGEMENTS
With thanks to "Zefram", "ilmari" and others from "irc.perl.org/#p5p" for assisting with trickier bits of
XS logic.
AUTHOR
Paul Evans <leonerd@leonerd.org.uk>
perl v5.30.0 2019-10-18 Syntax::Keyword::Try(3pm)