Skip to content

Commit

Permalink
README.md updates
Browse files Browse the repository at this point in the history
* FuturesExtra.join returns JoinedResults not JoinedResult
* Language updates and a bit of clarification
* Added type information to the lambdas that makes the
  example code for joining futures compile.
  • Loading branch information
Noa Resare committed Feb 22, 2015
1 parent c679253 commit 8f17a06
Showing 1 changed file with 23 additions and 16 deletions.
39 changes: 23 additions & 16 deletions README.md
Expand Up @@ -31,21 +31,25 @@ To import it with maven, use this:

#### Cleaner transforms for Java 8.
Java 8 introduced lambdas which can greatly reduce verbosity in code, which is
great when using futures and transforms.
great when using futures and transforms. One drawback with lambdas though is
that when a lambda is supplied as an argument to a method with overloaded
parameters, the compiler may fail to figure out which variant of a method call
that is intended to be used.

Ideally you would want to do something like this:
Ideally, applying java 8 lambdas to Guava's Futures.transform() would look
something like this:
```java
public static <A, B> ListenableFuture<B> example(ListenableFuture<A> future) {
return Futures.transform(future, a -> toB(a));
}
```

This doesn't actually work though, because Futures.transform has two variants:
one that takes a Function and one that takes an AsyncFunction.
Hence the compiler can't determine which variant to use without additional
type information.
Unfortunately this doesn't actually work because Futures.transform has
two variants: one that takes a Function as it's second parameter and one that

This comment has been minimized.

Copy link
@spkrka

spkrka Feb 22, 2015

Member

it's -> its

takes an AsyncFunction. The compiler can't determine which variant to use
without additional type information.

To work around that you have to cast it like this:
You could work around that you have to cast it like this:

This comment has been minimized.

Copy link
@spkrka

spkrka Feb 22, 2015

Member

"You could work around that by casting it like this"

```java
public static <A, B> ListenableFuture<B> example(ListenableFuture<A> future) {
return Futures.transform(future, (Function<A, B>) a -> toB(a));
Expand Down Expand Up @@ -76,19 +80,21 @@ becomes more verbose).
final ListenableFuture<A> futureA = getFutureA();
final ListenableFuture<B> futureB = getFutureB();

return Futures.transform(Futures.allAsList(futureA, futureB),
list -> combine((A) list.get(0), (B) list.get(1));
ListenableFuture<C> ret = Futures.transform(Futures.allAsList(futureA, futureB),
(Function<List<?>, C>)list -> combine((A) list.get(0), (B) list.get(1));
```
where combine is a method with parameters of type A and B returning C.

This one has the problem that you have to manually make sure that the casts and
ordering are correct, otherwise you will get ClassCastException.

You could also do this one instead to avoid casts:
You could also access the futures directly to avoid casts:
```java
final ListenableFuture<A> futureA = getFutureA();
final ListenableFuture<B> futureB = getFutureB();

return Futures.transform(Futures.allAsList(futureA, futureB),
list -> combine(getUnchecked(futureA), getUnchecked(futureB));
ListenableFuture<C> ret = Futures.transform(Futures.allAsList(futureA, futureB),
(Function<List<?>, C>)list -> combine(Futures.getUnchecked(futureA), Futures.getUnchecked(futureB));
```
Now you instead need to make sure that the futures in the transform input are
the same as the ones you getUnchecked. If you fail to do this, things may work
Expand All @@ -101,22 +107,23 @@ To simplify these use cases we have a couple of helper functions:
final ListenableFuture<A> futureA = getFutureA();
final ListenableFuture<B> futureB = getFutureB();

return FuturesExtra.syncTransform2(futureA, futureB,
ListenableFuture<C> FuturesExtra.syncTransform2(futureA, futureB,

This comment has been minimized.

Copy link
@spkrka

spkrka Feb 22, 2015

Member

missing variable name?

(a, b) -> combine(a, b));
```

This is much clearer! We don't need any type information because the lambda can
infer it, and we avoid the potential bugs that can occur as a result of the
first to examples.
The tuple transform can be used up to 6 arguments. If you need more than that,
some refactoring is likely in place, but you can also use the JoinedResult:
The tuple transform can be used up to 6 arguments named syncTransform2() through
syncTransform6(). If you need more than that you could probably benefit from
some refactoring, but you can also use FuturesExtra.join():
```java
final ListenableFuture<A> futureA = getFutureA();
final ListenableFuture<B> futureB = getFutureB();
final ListenableFuture<JoinedResult> futureJoined = FuturesExtra.join(futureA, futureB);
final ListenableFuture<JoinedResults> futureJoined = FuturesExtra.join(futureA, futureB);
return Futures.transform(futureJoined,
joined -> combine(joined.get(futureA), joined.get(futureB)));
```
Expand Down

0 comments on commit 8f17a06

Please sign in to comment.