NAME
FP::Failure - failure values
SYNOPSIS
use FP::Equal ':all'; use FP::Ops qw(the_method regex_substitute); use FP::List;
use FP::Failure;
is_equal \@FP::Failure::EXPORT, [qw(failure is_failure)];
# but there is more in EXPORT_OK...
use FP::Failure '*trace_failures';
my $vals = do {
local $trace_failures = 0;
list(failure("not good"),
failure(666),
failure(undef),
666,
0,
undef)
};
is_equal $vals->map(\&is_failure),
list(1, 1, 1, undef, undef, undef);
is_equal $vals->map(sub { my ($v) = @_; $v ? "t" : "f" }),
list("f", "f", "f", "t", "f", "f");
# failure dies when called in void context (for safety, failures have
# to be ignored *explicitly*):
is((eval { failure("hello"); 1 } || ref $@),
'FP::Failure::Failure');
# get the wrapped value
is_equal $vals->filter(\&is_failure)->map(the_method "value"),
list("not good", 666, undef);
# get a nice message
is_equal $vals->first->message,
"failure: 'not good'\n";
# record backtraces
my $v = do {
local $trace_failures = 1;
failure(666, [$vals->first])
};
is_equal $v->message,
"failure: 666\n because:\n failure: 'not good'\n";
# request recorded backtrace to be shown
use Path::Tiny;
is_equal regex_substitute(sub { # cleaning up bt
s/line \d+/line .../g;
my $btlines = 0;
$_ = join("\n",
grep { not /^ \S/ or ++$btlines < 2 }
split /\n/)
},
$v->message(1)),
join("\n", "failure: 666 at ".path("lib/FP/Failure.pm")->canonpath
." line ...",
" (eval) at lib/FP/Repl/WithRepl.pm line ...",
" because:",
" failure: 'not good'");
# Wrapper that just returns 0 unless configured to create a failure
# object:
use FP::Failure qw(*use_failure fails);
use FP::Show;
is show(do { local $use_failure = 0; fails("hi") }),
0;
is show(do { local $use_failure = 1; fails("hi") }),
"Failure('hi', undef, undef)";
# Utility container for holding both a message and values:
use FP::Failure qw(message messagefmt);
is failure(message "Hi", "foo", 9)->message,
"failure: Hi: 'foo', 9\n";
is failure(message "Hi")->message,
"failure: Hi\n";
# messagefmt is currently still passing everything through FP::Show;
# what should it do, implement another fmt character?
is failure(messagefmt "Hi %s %d", "foo", 9)->message,
"failure: Hi 'foo' 9\n";
DESCRIPTION
Values meant to represent errors/failures and to be distinguishable from non-error values. They are overloaded to be false in boolean context (although doing a boolean test is not safe to distinguish from non-failure values, as obviously those include false as well), or checked via the `is_failure` function.
The `value` method delivers the first argument given to `failure`, `maybe_parents` the second, which is an array of the parents, meant for chaining failures (reasons why this failure happened). `message` produces a somewhat nice to read string, multi-line if parents are chained in.
Calling the constructor in void context throws the constructed failure value as an exception.
If the variable `$FP::Failure::trace_failures` is set to true (it can be imported mutably via '*trace_failures'; default: false), then a stack trace is collected with the failures and displayed with `message` (if a true value is passed to message ?). (XX: use `BACKTRACE=1` idea here, too? Implement the same in `Chj::Backtrace`, too, and FP::Repl::Trap if fitting?)
If the variable `$FP::Failure::use_failure` is set to true (it can be imported mutably via '*use_failures'; default: false), then the optionally exported wrapper function `fails` calls `failure` with its arguments, otherwise it returns `0` (fully compatible with standard Perl booleans, and a little bit faster).
TODO
Instead of using `FP::Failure::Failure` as base class, create a failure protocol (FP::Abstract::Failure) instead?
SEE ALSO
FP::Either (which wraps both cases in a shared parent type).
Implements: FP::Abstract::Pure, FP::Struct::Show
NOTE
This is alpha software! Read the status section in the package README or on the website.