I believe I am facing an eclipse bug here, but I'd like to confirm.
I am using java 8 (jdk 1.8.0_102), and my code compiles normally, but eclipse gives me an error.
My code looks like this:
public ListenableFuture<ProtoBufExchange> myMethod(
//some code here
return Futures.transform(future,(Request.Builder reqBuilder) -> {
//some code here
return Futures.immediateFuture(exchange);
}
The error shown in eclipse is this:
The method transform(ListenableFuture<Request.Builder>, AsyncFunction<? super Request.Builder,? extends ProtoBufExchange>) is ambiguous for the type Futures.
If I put a cast, eclipse will not complain:
public ListenableFuture<ProtoBufExchange> myMethod(
//some code here
return Futures.transform(future,(AsyncFunction<Request.Builder, ProtoBufExchange>) (Request.Builder reqBuilder) -> {
//some code here
return Futures.immediateFuture(exchange);
}
I know the guava 15.0 Future.transform() is overloaded, with the two forms below (on newer guava versions the async method has a different name):
transform(ListenableFuture<I> input, Function<? super I,? extends O> function)
or
transform(ListenableFuture<I> input, AsyncFunction<? super I,? extends O> function)
But somehow the jdk compiler resolves this ambiguation. Maybe because in the code above, if we were implementing a Function, rather than an AsyncFunction, the return type of Futures.transform would not match with the method return type.
Is it a bug on eclipse? Am I missing something here?
More details on my environment:
jdk: 1.8.0_102
eclipse: 4.6.2
guava: 15.0
There is a distinction between “explicitly typed lambda expressions” and “implicitly typed lambda expressions”.
An implicitly typed lambda expression of the form
name -> expressiorOrBlock
or(name[,name]*) -> expressionOrBlock
requires its context, i.e. a resolved method, to determine its type, hence isn’t used to disambiguate overloaded methods. It wouldn’t be impossible to do this, but due to the resulting complexity, it was explicitly ruled out by the specification.Explicitly typed lambda expressions of the form
(Type name[, Type name]*) -> expressionOrBlock
have everything needed to determine their functional signature, including their return type, which allows to use them to disambiguate overloaded methods.To provide a simple example:
The formal rules are specified in JLS, §15.12.2.5. Choosing the Most Specific Method, but it also contains an informal hint:
I think, it’s easy to see that every call that can be handled by
method(AF)
could also be handled bymethod(F)
, while the opposite doesn’t apply, i.e. themethod((Object x) -> "bla")
invocation can only be handled bymethod(F)
, so it’s not ambiguous, whereasmethod((Object x) -> new FutureTask<String>(null))
could be handled by both, butmethod(AF)
is more specific.The relevant formal part is:
So in this specific case involving an explicitly typed lambda expression, the return type of the functional type is already sufficient to disambiguate.
But note that compiling the example code also produces the warning:
Reminding that implicitly typed lambda expressions will always be ambiguous with such overloaded methods and also the method selection with explicitly type lambda expressions might not be intuitive.