Reputation: 20843
Why is the compiler able to determine the generic type parameter for an
assignment, but not for the ternary operator (?
)?
I have a question regarding the compiler being able to deduce the generic type
parameter in case of a "direct" assignment but failing in case of the ternary
operator (?
). My examples uses Guava's Optional
class, to make my point, but
I think the underlying issue is generic and not restricted to Optional
.
Optional
has a generic function absent()
:
public static <T> Optional<T> absent();
and I can assign an Optional<T>
to an Optional<Double>
:
// no compiler error
final Optional<Double> o1 = Optional.absent();
How does the compiler realize, that T
should be Double
in this case. Because
when using the ternary operator (?
), I need to tell the compiler specifically
to us Integer
as the generic parameter
// Type mismatch: cannot convert from Optional<capture#1-of ? extends Object> to Optional<Integer>
final Optional<Integer> o2 = true
? Optional.of(42)
: Optional.<Integer>absent();
otherwise I get the following error
Type mismatch: cannot convert from
Optional<capture#1-of ? extends Object>
toOptional<Integer>
Why is there a difference between a "direct" assignement and using the ternary operator? Or is there something else I am missing?
Upvotes: 17
Views: 1135
Reputation: 49372
Because of type inference rules, it appears the ternary expression does not infer the type parameter from the return type. The type of the ternary expression depends on the types of its operands. But one of the operands has undetermined type parameter (Optional.absent()
). At that point the ternary expression still does not have a type, so it cannot influence the type parameter.
You can also look into this bug report for more information. You can look into the JLS .
The type of the conditional expression is the result of applying capture conversion (??5.1.10) to lub(T1, T2)
Here what the JLS says :
If the method result occurs in a context where it will be subject to assignment conversion to a type S, then let R be the declared result type of the method, and let R' = R[T1 = B(T1) ... Tn = B(Tn)] where B(Ti) is the type inferred for Ti in the previous section, or Ti if no type was inferred.
Upvotes: 9
Reputation: 2843
The Problem is that the result of the ternery Operator is assigned to o2. The compiler can't deduce the type across multiple operations.
Basically I think you write the short form of:
Optional<?> tmp = true ? Optional.of(42): Optional.absent();
final Optional<Integer> o2 = tmp;
The conversion of the second line is the problem.
Upvotes: 5