Promises::Cookbook::ScalaFuturesComparison - A comparison of Scala Futures with Promises
version 0.99
Here is the example Scala code, it assumes a function called fetch which when given a URL will return a Future.
fetch
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:
get_thumbnail
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.
flatMap
getThumbnail
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.
then
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.
rescue
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 ...
Systems Programming at Twitter - http://monkey.org/~marius/talks/twittersystems/
Stevan Little <stevan.little@iinteractive.com>
This software is copyright (c) 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.
To install Promises, copy and paste the appropriate command in to your terminal.
cpanm
cpanm Promises
CPAN shell
perl -MCPAN -e shell install Promises
For more information on module installation, please visit the detailed CPAN module installation guide.