NAME
Promises::Cookbook::ScalaFuturesComparison - A comparison of Scala Futures with Promises
VERSION
version 1.01
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) 2019, 2017, 2014, 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.