guava
guava copied to clipboard
Feature request: add support for transforming a tuple of futures into a single future
Original issue created by kristofer.karlsson on 2013-05-22 at 03:01 PM
Sometimes it would be useful to combine the result of multiple futures into a single result, basically transforming a set of futures into a single future.
This is already supported to some extent through Futures.allAsList, but that only works if all futures are of the same type. I would want something similar, but that works on tuples instead of lists.
Something like this: ListenableFuture<A> future1; ListenableFuture<B> future1; Function2<X, A, B> function = new Function2<X, A, B>(){ @Override public X apply(A first, B second) { return merge(first, second); } }; ListenableFuture<X> result = Futures.transform(future1, future2, function);
Attached is some sort of minimal implementation of this concept.
Original comment posted by [email protected] on 2013-05-22 at 03:09 PM
Though we've stayed away from Function2 and friends (<https://code.google.com/p/guava-libraries/wiki/IdeaGraveyard#Functions/Predicates_for_n_%3E=_2_inputs>), we can find other ways of merging Futures:
final ListenableFuture<A> future1; final ListenableFuture<B> future2; Callable<X> function = new Callable<X>() { @Override public X call() { return merge(future1.get(), future2.get()); } }; ListenableFuture<X> result = Futures.combine(function, executor, future1, future2);
In fact, we have this method internally. It may yet make its way out.
Original comment posted by kristofer.karlsson on 2013-05-22 at 03:19 PM
Thanks for quick response. But if that's the route you're going for it, I could just wrap things as a list instead and do this:
final ListenableFuture<A> future1; final ListenableFuture<B> future1; Function<X, ?> function = new Function<X, ?>(){ @Override public X apply(List<?> dummy) { return merge(future1.get(), future2.get()); } }; ListenableFuture<X> result = Futures.transform(Futures.allAsList(future1, future2), function);
so you wouldn't actually need to expose your combine. The tuple version is cute, since it gives somewhat nicer type information, and you don't need to invoke outer objects.
You could also do this, but I'm not sure it's any prettier: ListenableFuture<A> future1; ListenableFuture<B> future1; Function<X, ?> function = new Function<X, ?>(){ @Override public X apply(List<?> result) { return merge((A) result.get(0), (B) result.get(0)); } }; ListenableFuture<X> result = Futures.transform(Futures.allAsList(future1, future2), function);
Original comment posted by [email protected] on 2013-05-22 at 03:27 PM
Yep, allAsList+transform is pretty much how ours is implemented. (As it turns out, ours (a) uses successfulAsList so that you can choose to handle exceptions manually (or just let them propagate) and (b) uses the AsyncFunction version of transform() so that the Function can throw any kind of Exception (important in part because we make you call get() but also sometimes convenient for other reasons.)
Part of what keeps us from going to tuple route is that, if we're going to address complex graphs of Futures, we probably want to go even further than an added method or two. There's at least one popular system available internally at Google, so we're kind of spoiled.
Original comment posted by pettermahlen on 2014-01-31 at 09:24 AM
We've created a framework that aims to simplify the problem of working with non-trivial asynchronous call graphs: https://github.com/spotify/trickle. It may be of interest until the day when the Google-internal system is made available to the public.
Let's call this the bug for de-@Beta-ing the FutureCombiner type.
This is now fixed.
While I did say...
Let's call this the bug for de-
@Beta-ing theFutureCombinertype.
...I think I had written that under the assumption that we wouldn't be de-@Beta-ing it until we added the functionality described in the initial post here. So let's have this open to track such an enhancement, even though we remain unlikely to do it anytime soon :(