Pau Cervera
and 1 contributors

NAME

Error::ROP - A simple and lightweight implementation error handling library for Perl, inspired in the Rop type.

SYNOPSIS

    use Error::ROP qw(rop);

    my $meaning =  rop { 80 / $divisor }->then(sub { $_ + 2 });

    say "The life meaning is " . $meaning->value if $meaning->is_valid;
    warn "Life has no meaning" if not $meaning->is_valid;

DESCRIPTION

The purpose of the rop function is to let you focus in the happy path and provide a nice way to treat failures without filling the code with evals and ifs that always serve almost the same purpose.

Supose you have a computation that can fail depending on some condition. For the sake of simplicity consider the following code

    sub compute_meaning {
        my $divisor = shift;
        return 2 + 80 / $divisor;
    };

that will fail when called with a zero argument.

Following the style of the Railway Oriented Programming, you wrap the part that could fail in a rop block and focus on programming the happy path:

    sub compute_meaning {
        my $divisor = shift;
        return rop { 80 / $divisor }
               ->then(sub { $_ + 2 });
    };

This way, the compute_meaning function will never blow, even when passed in a zero argument and the computation doesn't make sense. The caller can check that the computation succeeded by asking the rop result object.

When the computation succeeds, the value property contains the computation result

    my $meaning = compute_meaning(2);
    say "The life meaning is " $meaning->value if $meaning->is_valid;

and when the computation fails, you can also inform the user or decide how to proceed, by inspecting the failure value, which will contain the captured error.

    my $meaning = compute_meaning(0);
    warn "Life has no meaning: " . $meaning->failure if not $meaning->is_valid;

Chaining

The real usability gain of using rop occurs when you have a recipe that comprises several things to do and you need to stop at the first step that fails.

That is, you need to chain or compose several functions that in the happy path would be executed one after another but in the real path, you would have to check for any of them if had failed or not and proceed with the next or stop and report the errors.

With rop you can leverage the checking to the library and just program the happy path functions and chain them with the then method:

  use Error::ROP;

  my $res = rop { 40 / $something }
    ->then(sub { $_ / 2 })
    ->then(sub { $_ * 4 })
    ->then(sub { $_ + 2 });

You can always know if the computation has succed by inspecting the rop,

    say $res->value if $res->is_valid;

or treat the error otherwise

    warn $res->failure if not $res->is_valid;

The computation will short-circuit and return with the first error occurred, no matter how many chained functions remain after the failing step.

On Either types and then

This module does not implement the Either type in Perl. The Haskell, F#, ML and other strongly typed functional programming languages have Either types. This is not a generic type like Haskell's Either a b.

On those PL you have a strong type system and generic programming facilities that allow you to generalize operations into higher abstractions. In particular, you can operate in elevated (monadic) types as if they where first class values and the languages provide tools (generic functions and operators) that allow you to compose those operations by somehow overloading composition.

When adopting an Either type to implement ROP in those languages, you normally use the >=> operator to overload composition. Actually, you use it to compose functions of the type

  >=> :: (a -> Either b e) -> (b -> Either c e) -> (a -> Either c e)

This library just uses a wrapper object (the Error::ROP instance) that has a method then to somehow compose other operations. This is a much less flexible approach but it works and is easy to understand. The two leaves of the type are accessible via the instance's value and failure getters.

The only confusion might be that it ressembles the then function of a promise or future. This is not exactly the same. Just keep that in mind.

USAGE

You can find more usage examples in the tests t/Then.t. For examples of how to use inside Moose t/Example.t

Running tests

A Dockerfile is provided in order to run the tests without needing any perl in your system. Just run:

  $ make -f Makefile.docker test

This should construct an image with the necessary dependencies, copy the source into the image and run the tests.

AUTHOR

Pau Cervera i Badia

CAPSiDE

BUGS and SOURCE

The source code is located here: https://github.com/paudirac/Error-ROP

Please report bugs to: https://github.com/paudirac/Error-ROP/issues

COPYRIGHT and LICENSE

Copyright (c) 2017 by CAPSiDE

This code is distributed under the Apache 2 License. The full text of the license can be found in the LICENSE file included with this module.