JEP 101: Generalized Target-Type Inference

OwnerMaurizio Cimadamore
TypeFeature
ScopeSE
StatusClosed / Delivered
Release8
Componentspecification / language
JSR335
Discussionlambda dash dev at openjdk dot java dot net
EffortM
DurationM
DependsJEP 126: Lambda Expressions & Virtual Extension Methods
Reviewed byBrian Goetz
Endorsed byBrian Goetz
Created2011/02/22 20:00
Updated2015/02/26 22:25
Issue8046091

Summary

Smoothly expand the scope of method type-inference to support (i) inference in method context and (ii) inference in chained calls.

Goals

Non-Goals

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