The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
package Promises::Cookbook::ScalaFuturesComparison;

# ABSTRACT: A comparison of Scala Futures with Promises

__END__

=pod

=head1 NAME

Promises::Cookbook::ScalaFuturesComparison - A comparison of Scala Futures with Promises

=head1 VERSION

version 0.96

=head1 DESCRIPTION

Here is the example Scala code, it assumes a function called C<fetch> 
which when given a URL will return a Future.

    def getThumbnail(url: String): Future[Webpage] = {
        val promise = new Promise[Webpage]
        fetch(url) onSuccess { page =>
            fetch(page.imageLinks(0)) onSuccess { p =>
                promise.setValue(p)
            } onFailure { exc =>
                promise.setException(exc)
            }
        } onFailure { exc =>
            promise.setException(exc)
        }
        promise
    }

If we take this and translate this into Perl code using the 
L<Mojo::UserAgent> library, the C<fetch> function would look 
like this:

    sub fetch {
        state $ua = Mojo::UserAgent->new;
        my $url   = shift;
        my $d     = deferred;
        $ua->get($url => sub {
            my ($ua, $tx) = @_;
            $d->resolve( $tx );
        });
        $d->promise;
    }

And if we were to take the C<get_thumbnail> function and 
translate it exactly, we would end up with this:

    sub get_thumbnail {
        my $url = shift;
        my $d   = deferred;
        fetch( $url )->then(
            sub {
                my $tx = shift;
                fetch( $tx->res->dom->find('img')->[0]->{'src'} )->then(
                    sub { $d->resolve( $_[0] ) },
                    sub { $d->reject( $_[0] ) },                
                )
            },
            sub { $d->reject( $_[0] ) }
        );
        $d->promise;
    }

Scala Futures have a method called C<flatMap>, which takes a 
function that given value will return another Future. Here is 
an example of how the C<getThumbnail> method can be simplified
by using it.

    def getThumbnail(url: String): Future[Webpage] =
        fetch(url) flatMap { page =>
             fetch(page.imageLinks(0))
        }

But since our C<then> method actually creates a new promise 
and wraps the callbacks to chain to that promise, we don't 
need this C<flatMap> combinator and so this, Just Works.

    sub get_thumbnail {
        my $url = shift;
        fetch( $url )->then(
            sub {
                my $tx = shift;
                fetch( $tx->res->dom->find('img')->[0]->{'src'} );
            }        
        );
    }

Scala Futures also have a C<rescue> method which can serve as 
a kind of catch block that potentially will return another 
Future.

    val f = fetch(url) rescue {
        case ConnectionFailed =>
          fetch(url)
    }

Just as with C<flatMap>, since our callbacks are wrapped and 
chained with a new Promise, we can do a rescue just by using 
the error callback The Promise returned by C<fetch> will get 
chained and so this will depend on it.

    sub get_thumbnail {
        my $url = shift;
        fetch( $url )->then(
            sub {
                my $page = shift;
                fetch( $page->image_links->[0] );
            },
            sub {
                given ( $_[0] ) {
                    when ('connection_failed') {
                        return fetch( $url );
                    }
                    default {
                        return "failed";
                    }
                }
            }
        );
    }

TODO ... figure out how retry can be generic ...

=head1 SEE ALSO

Systems Programming at Twitter - L<http://monkey.org/~marius/talks/twittersystems/>

=head1 AUTHOR

Stevan Little <stevan.little@iinteractive.com>

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2014 by Infinity Interactive, Inc..

This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.

=cut