dwww Home | Manual pages | Find package

Syntax::Keyword::Try(3User Contributed Perl DocumentaSyntax::Keyword::Try(3pm)

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 ($e) {
                warn "It failed - $e";
                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.

       Syntax similar to this module has now been added to core perl, starting
       at version 5.34.0. If you are writing new code, it is suggested that
       you instead use the Feature::Compat::Try module instead, as that will
       enable the core feature on those supported perl versions, falling back
       to "Syntax::Keyword::Try" on older perls.

Experimental Features
       Some of the features of this module are currently marked as
       experimental. They will provoke warnings in the "experimental"
       category, unless silenced.

       You can silence this with "no warnings 'experimental'" but then that
       will silence every experimental warning, which may hide others
       unintentionally. For a more fine-grained approach you can instead use
       the import line for this module to only silence this module's warnings
       selectively:

          use Syntax::Keyword::Try qw( try :experimental(typed) );

          use Syntax::Keyword::Try qw( try :experimental );  # all of the above

       Don't forget to import the main "try" symbol itself, to activate the
       syntax.

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.

       Even though it parses as a statement and not an expression, a "try"
       block can still yield a value if it appears as the final statement in
       its containing "sub" or "do" block. For example:

          my $result = do {
             try { attempt_func() }
             catch ($e) { "Fallback Value" }
          };

       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 ($var) {
             STATEMENTS...
          }

       or

          ...
          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. Optionally a new lexical variable can be provided
       to store the exception in. If not provided, the "catch" block can
       inspect the raised exception by looking in $@ instead.

       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.

   catch (Typed)
          ...
          catch ($var isa Class) { ... }

          ...
          catch ($var =~ m/^Regexp match/) { ... }

       Experimental; since version 0.15.

       Optionally, multiple catch statements can be provided, where each block
       is given a guarding condition, to control whether or not it will catch
       particular exception values. Use of this syntax will provoke an
       "experimental" category warning on supporting perl versions, unless
       silenced by importing the ":experimental(typed)" tag (see above).

       Two kinds of condition are supported:

       •

              catch ($var isa Class)

           The block is invoked only if the caught exception is a blessed
           object, and derives from the given package name.

           On Perl version 5.32 onwards, this condition test is implemented
           using the same op type that the core "$var isa Class" syntax is
           provided by and works in exactly the same way.

           On older perl versions it is emulated by a compatibility function.
           Currently this function does not respect a "->isa" method overload
           on the exception instance. Usually this should not be a problem, as
           exception class types rarely provide such a method.

       •

              catch ($var =~ m/regexp/)

           The block is invoked only if the caught exception is a string that
           matches the given regexp.

       When an exception is caught, each condition is tested in the order they
       are written in, until a matching case is found. If such a case is found
       the corresponding block is invoked, and no further condition is tested.
       If no contional block matched and there is a default (unconditional)
       block at the end then that is invoked instead. If no such block exists,
       then the exception is propagated up to the calling scope.

   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.

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

       In addition, core perl itself gained a "try/catch" syntax based on this
       module at version 5.34.0. It is available as "use 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.

       The core "feature 'try'" is also implemented as true native syntax in
       the perl parser.

       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.

       The core "feature 'try'" also behaves in this manner.

   "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.

       It also behaves this way using the core "feature 'try'".

       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.

       These also work fine when using the core "feature 'try'".

       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. You
       cannot assign from the result of a "try" block. A common workaround is
       to wrap the "try/catch" statement inside a "do" block, where its final
       expression can be captured and used as a value.

       The same "do" block wrapping also works for the core "feature 'try'".

       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.

   "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".

       The core "feature 'try'" does not implement "finally" at all, and also
       requires that every "try" block be followed by a "catch".

   Typed "catch"
       Try and Try::Tiny make no attempt to perform any kind of typed dispatch
       to distinguish kinds of exception caught by "catch" blocks.

       Likewise the core "feature 'try'" currently does not provide this
       ability, though it remains an area of ongoing design work.

       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.

       This module provides such an ability, via the currently-experimental
       "catch (VAR cond...)" syntax.

       The design thoughts continue on the RT ticket
       <https://rt.cpan.org/Ticket/Display.html?id=123918>.

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";
             }
          }

ISSUES
   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.36.0                      2022-12-16         Syntax::Keyword::Try(3pm)

Generated by dwww version 1.15 on Mon Jul 1 01:37:12 CEST 2024.