JEP 101: Generalized Target-Type Inference
Summary
Smoothly expand the scope of method type-inference to support (i) inference in method context and (ii) inference in chained calls.
Goals
- Add support for method type-parameter inference in method context
- Add support for method type-parameter inference in chained calls
Non-Goals
- Global type-inference
Success Metrics
Improve usability of generics by reducing method type-inference corner cases. Improve readability of code by reducing explicit type-arguments in generic method calls.
Motivation
Type-arguments in generic method calls are automatically inferred by the compiler since JDK 5. Type-inference is important not only as explicit type arguments are somewhat awkward and verbose, but primarily because many programmers are unfamiliar with them and, as a result, are unable to cope with situations where type-argument inference fails to give the correct answer. It is thus important to minimize cases in which method type-inference fails; we believe method type-inference could be greatly improved by adding the support for following features (i) inference in argument position and (ii) inference in chained calls.
Description
Here we propose some improvements to the existing type-argument inference support that will significantly reduce the need for explicit type-arguments in generic method calls.
i. Inference in argument position
Consider the following class declaration:
class List<E> {
static <Z> List<Z> nil() { ... };
static <Z> List<Z> cons(Z head, List<Z> tail) { ... };
E head() { ... }
}
The result of a generic method, such as List.nil() may be inferred from the right-hand side of an assignment:
List<String> ls = List.nil();
The compiler's type-inference mechanism figures out that the type-argument to the List.nil() call is indeed String. It seems reasonable that the compiler should be able to infer the type when the result of such a generic method invocation is passed to another method, as below:
List.cons(42, List.nil()); //error: expected List<Integer>, found List<Object>
Unfortunately, this is not allowed in JDK 5/6/7 -- the only option available to the programmer is to use an explicit type-argument:
List.cons(42, List.<Integer>nil());
It would be nice if type-argument inference would be extended to consider the formal parameter type in a method call (target typing).
ii. Inference in chained calls
Another fairly common problem is when generic method calls are chained together, as below:
String s = List.nil().head(); //error: expected String, found Object
The right-hand type in the above assignment is unused during type-argument inference -- as a result, the only option for the programmer is (again) to manually specify type-arguments, as in:
String s = List.<String>nil().head();
Again, it would be nice to remove the burden of explicit type-arguments by allowing the right-hand type of the assignment (String) to flow through the chain of generic method calls.
Alternatives
Manually specify type-parameters (as today).
Testing
Need to verify that the new inference algorithm behaves as expected. Need to verify that the new inference algorithm doesn't break backward compatibility in unexpected ways (or need to ensure that cases in which backward compatibility is not preserved are sufficiently rare).
There are no special platform or hardware requirements.
Risks and Assumptions
As pointed out above, the primary risk of this change is that any change affecting method type-inference has the potential for backwards incompatibility. Since the changes described in this document affect a delicate area of the Java language/compiler (type-system), test resources are needed to check that the proposed change do not affect backward compatibility in unexpected ways. If needed, a prototype supporting the described feature can be provided in a relatively short timeframe (i.e. before Project Lambda is complete).
Dependences
This work depends on the Project Lambda JEP -- Project Lambda requires a novel way of type-inference, called target-typing inference, that is used to infer the type of the formals of a lambda expression from the context in which the lambda expression is used. Part of this work (inference in method context) is simply a generalization of the approach exploited in project lambda. Another part of this work (inference in chained calls) is an inference improvements that will help adoption of Project Lambda for developing LinQ-like.
Impact
- Customers: more readable code (less explicit type-arguments) -- easier to use generic methods/constructor/diamond.
- CCC: A CCC will be required to cover the type-inference changes
- Compatibility: The new inference scheme might alter the set of compilable programs in a subtle way -- it is crucial that JCK team will test the changes.
- Doc: None
- JCP: None
- L10N: Minimal impact: likely to add new error messages