Quick actions

cmd+k|ctrl+k

Navigation

Languages

[Raku] `trys`

Snippet info

Language

Raku

Visibility

public

Author

raiph.mellor

Created

2021-08-02T16:06:55.976355Z

Updated

2022-03-06T17:13:08.15936Z

# See https://stackoverflow.com/questions/51644197

use lib '.';

# `trys` in detail

use X2;

# `trys` tries a list of callables, short circuiting if one "works":
say trys {die}, {42}, {fail}                  # 42

# By default, "works" means no exception thrown and result is not a `Failure`:
say trys {die}, {fail}, {42}                  # 42

# An (optional) `:reject` argument lets you specify
# value(s) you want rejected if they smartmatch:
say trys :reject(Nil,/o/), {Nil}, {'no'}, {2} # 2

# If all callables throw, return `Failure` wrapping exceptions(s):
say trys :reject(Nil), {Nil}                  # (HANDLED) Rejected Nil
say trys {die}                                # (HANDLED) Died
say trys {(42/0).Str}                         # (HANDLED) Attempt to divide by zero
# Specify `:!HANDLED` if the returned `Failure` is to be left unhandled:
say (trys {(42/0).Str}, :!HANDLED) .handled;  # False

# The first callable is passed the caller's current exception as its topic:
$! = X::AdHoc.new: payload => 'foo';
trys {.say}                                   # foo

# Topic of subsequent callables is exception from prior failed callable:
trys {die 'bar'}, *.say;                      # bar
trys {fail 'bar'}, {die "$_ baz"}, *.say;     # bar baz

# Caller's `$!` is left alone (presuming no `trys` bug):
say $!;                                       # foo

# To include *all* throws in `Failure`, specify `:all-throws`:
say trys {die 1}, {die 2}, :all-throws;       # (HANDLED) foo 1 2
# Note the `foo` -- `all-throws` includes the caller's original `$!`.
```

# `trys` "traps"

```
# Some "traps" are specific to the way `trys` works:

say trys { ... } // 42;                   # "(HANDLED) Stub code executed"
say trys { ... }, { 42 }                  # 42 <-- List of blocks, no `//`.

#trys 22;                                 # Type check failed ... got Int (22)
say trys { 22 }                           # 22 <-- Block, not statement.

#trys {}                                  # Type check failed ... got Hash ({})
say trys {;}                              # Nil <-- Block, not Hash.

# Other "traps" are due to the way Raku works:

# WAT `False` result if callable has `when`s but none match:
say do   {when rand { 42 }}               # False <-- It's how Raku works.
say trys {when rand { 42 }}               # False <-- So same with `trys`.
say trys {when rand { 42 }; Nil}          # Nil <-- Succinct fix.
say trys {when rand { 42 }; default {}}   # Nil <-- Verbose fix.

# Surprise `(Any)` result if callable's last/return value is explicitly `$!`:
$! = X::AdHoc.new: payload => 'foo';
say try {$!}                              # (Any) <-- Builtin `try` clears `$!`.
say $!;                                   # (Any) <-- Caller's too!
$! = X::AdHoc.new: payload => 'foo';
say trys {$!}                             # (Any) <-- `trys` clears `$!` BUT:
say $!;                                   # foo <-- Caller's `$!` left alone.
$! = X::AdHoc.new: payload => 'foo';
say try {$!.self}                         # foo <-- A fix with builtin `try`.
say $!;                                   # (Any) <-- Caller's `$!` still gone.
$! = X::AdHoc.new: payload => 'foo';
say trys {.self}                          # foo <-- Similar fix with `trys`.
say $!;                                   # foo <-- Caller's `$!` left alone.
INFO