|
NAMEPromises::Cookbook::ScalaFuturesComparison - A comparison of Scala Futures with Promises VERSIONversion 0.94 DESCRIPTIONHere 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 ALSOSystems Programming at Twitter - <http://monkey.org/~marius/talks/twittersystems/> AUTHORStevan Little <stevan.little@iinteractive.com> COPYRIGHT AND LICENSEThis 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.
|