Failure is a soft or unthrown Exception, usually generated by calling
&fail. It acts as a wrapper around an Exception object.
Sink (void) context causes a
Failure to throw, i.e. turn into a regular exception. The
use fatal pragma causes this to happen in all contexts within the pragma's scope. Inside
use fatal is automatically set, and you can disable it with
That means that Failures are generally only useful in cases of code that normally would produce an rvalue; Failures are more or less equivalent to Exceptions in code that will frequently be called in sink context (i.e., for its side-effects, such as with
Similarly, you should generally use
&fail only inside code that is normally expected to return something.
Checking a Failure for truth (with the
Bool method) or definedness (with the
defined method) marks the failure as handled, and causes it not to throw in sink context anymore.
You can call the
handled method to check if a failure has been handled.
Calling methods on unhandled failures propagates the failure. The specification says the result is another
Failure; in Rakudo it causes the failure to throw.
Because a Failure is
Nil, which is undefined, a common idiom for safely executing code that may fail uses a
sub may_fail( --> Numeric )with may_fail() ->else
multi method new(Failure:)multi method new(Failure:)multi method new(Failure: Exception \exception)multi method new(Failure: )multi method new(Failure: |cap (*))
Returns a new
Failure instance with payload given as argument. If called without arguments on a
Failure object, it will throw; on a type value, it will create an empty
Failure with no payload. The latter can be either an Exception or a payload for an
Exception. A typical payload would be a
Str with an error message. A list of payloads is also accepted.
my = Failure.new(now.DateTime, 'WELP‼');say ;CATCH# OUTPUT: «X::AdHoc: 2017-09-10T11:56:05.477237ZWELP‼␤»
method handled(Failure: --> Bool) is rw
True for handled failures,
sub f() ; my = f; say .handled; # OUTPUT: «False␤»
handled method is an lvalue, see routine trait
is rw, which means you can also use it to set the handled state:
sub f()my = f;.handled = True;say .handled; # OUTPUT: «True␤»
method exception(Failure: --> Exception)
Returns the Exception object that the failure wraps.
sub failer() ;my = failer;my = .exception;put "$ex.^name(): $ex";# OUTPUT: «X::AdHoc: Failed␤»
method self(Failure: --> Failure)
If the invocant is a handled
Failure, returns it as is. If not handled, throws its Exception. Since Mu type provides
.self for every class, calling this method is a handy way to explosively filter out Failures:
my = '♥'.Int;# $num1 now contains a Failure object, which may not be desirablemy = '♥'.Int.self;# .self method call on Failure causes an exception to be thrownmy = '42'.Int.self;# Int type has a .self method, so here $num3 has `42` in it(my = '♥'.Int).so;say .self; # OUTPUT: «(HANDLED) Cannot convert string to number…»# Here, Failure is handled, so .self just returns it as is
multi method Bool(Failure: --> Bool)
False, and marks the failure as handled.
sub f() ;my = f;say .handled; # OUTPUT: «False␤»say .Bool; # OUTPUT: «False␤»say .handled; # OUTPUT: «True␤»
X::Cannot::Capture if the invocant is a type object or a handled Failure. Otherwise, throws the invocant's exception.
multi method defined(Failure: --> Bool)
False (failures are officially undefined), and marks the failure as handled.
sub f() ;my = f;say .handled; # OUTPUT: «False␤»say .defined; # OUTPUT: «False␤»say .handled; # OUTPUT: «True␤»
multi method list(Failure:)
Marks the failure as handled and throws the invocant's exception.
multi sub fail(--> Nil)multi sub fail(*)multi sub fail(Exception --> Nil )multi sub fail( --> Nil)multi sub fail(|cap (*) --> Nil)multi sub fail(Failure --> Nil)multi sub fail(Failure --> Nil)
Exits the calling
Routine and returns a Failure object wrapping the exception
$e - or, for the
$payload form, an X::AdHoc exception constructed from the concatenation of
@text. If the caller activated fatal exceptions via the pragma
use fatal;, the exception is thrown instead of being returned as a
# A custom exception definedis Exceptionsub copy-directory-tree ()# A Failure with X::AdHoc exception object is returned and# assigned, so no throwing Would be thrown without an assignmentmy = copy-directory-tree("cat.jpg");say .exception; # OUTPUT: «cat.jpg is not a directory␤»# A Failure with a custom Exception object is returned= copy-directory-tree('foo');say .exception; # OUTPUT: «This directory is forbidden: 'foo'␤»
If it's called with a generic
Failure, an ad-hoc undefined failure is thrown; if it's a defined
Failure, it will be marked as unhandled.
sub re-failmy = re-fail;say .handled; # OUTPUT: «False␤»