NAME
Promises::Cookbook::ScalaFuturesComparison - A comparison of Scala Futures with Promises
VERSION
version 0.06
DESCRIPTION
Here is the example Scala code, it assumes a function called 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 Mojo::UserAgent library, the 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 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 flatMap
, which takes a function that given value will return another Future. Here is an example of how the 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 then
method actually creates a new promise and wraps the callbacks to chain to that promise, we don't need this 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 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 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 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 ...
SEE ALSO
Systems Programming at Twitter - http://monkey.org/~marius/talks/twittersystems/
AUTHOR
Stevan Little <stevan.little@iinteractive.com>
COPYRIGHT AND LICENSE
This software is copyright (c) 2012 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.