I have a weird scenario where type inference isn\'t working as I\'d expect when using a lambda expression. Here\'s an approximation of my real scenario:
stat
Inference on lambda parameter type cannot depend on the lambda body.
The compiler faces a tough job trying to make sense of implicit lambda expressions
foo( value -> GIBBERISH )
The type of value
must be inferred first before GIBBERISH can be compiled, because in general the interpretation of GIBBERISH depends on the definition of value
.
(In your special case, GIBBERISH happens to be a simple constant independent of value
.)
Javac must infer Value
first for parameter value
; there's no constraints in context, therefore T=Object
. Then, lambda body true
is compiled and recognized as Boolean, compatible with T
.
After you made the change to the functional interface, the lambda parameter type does not require inference; T remains uninfered. Next, the lambda body is compiled, and the return type appears to be Boolean, which is set as a lower bound for T
.
Another example demonstrating the issue
void foo(T v, Function f) { ... }
foo("", v->42); // Error. why can't javac infer T=Object ?
T is inferred to be String
; the body of lambda did not participate in the inference.
In this example, javac's behavior seems very reasonable to us; it likely prevented a programming error. You don't want inference to be too powerful; if everything we write compiles somehow, we'll lose the confidence on compiler finding errors for us.
There are other examples where lambda body appears to provide unequivocal constraints, yet the compiler cannot use that information. In Java, the lambda parameter types must be fixed first, before the body can be looked at. This is a deliberate decision. In contrast, C# is willing to try different parameter types and see which makes the code compile. Java considers that too risky.
In any case, when implicit lambda fails, which happens rather frequently, provide explicit types for lambda parameters; in your case, (Value