The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

FP::Failure - failure values

SYNOPSIS

 use FP::Equal ':all'; use FP::Ops qw(the_method); 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
 is_equal $v->message(1),
          join("\n", "failure: 666 at lib/FP/Failure.pm line 54",
                     "    (eval) at t/pod_snippets line 126",
                     "  because:",
                     "  failure: 'not good'\n");


 # 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?