Does Java fail to deduce the generic type parameter when using the ternary operator (`?`)?

generics, java

Solution

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.

Problem

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>` to `Optional<Integer>` Why is there a difference between a "direct" assignement and using the ternary operator? Or is there something else I am missing?

Original source