on diamond and evolution

Maurizio Cimadamore Maurizio.Cimadamore at Sun.COM
Fri Nov 6 03:31:15 PST 2009


Hi
Following the recent discussions in this mailing list about the diamond 
implementation, I decided to spent some more time in order to figure 
out  exactly what it means, in term of language evolution, supporting 
the simple approach currently checked in the JDK 7 repository.

Quick recap:

*) Simple approach: infers the diamond type using the *only* the 
expected type (if available) - similar (if not identical) to 15.12.2.8

*) Complex approach: infers the diamond type using a full inference 
round (arguments + return type) - 15.12.2.7 + 15.12.2.8

*) Full-complex approach: an hypothetical approach that is based upon 
complex (see above) - in addition, it throws the constraint about the 
expected type earlier in the inference process (precisely in 15.12.2.7), 
so that argument type inference cannot infer a type that, by being too 
specific, is incompatible with the expected type.

As it was shown in [1] there is no subset relationship between simple 
and complex - that is the two inference routines simply yield different 
results - in this sense, the simple approach cannot be viewed as a 
proper subset of the complex approach.

This is bad for evolution, as pointed out by Neal. My argument was that 
there existed a full-complex approach capable of subsuming both simple 
and complex at the same time - this would have allowed for further 
language extension (e.g. argument type inference) w/o breaking 
compatibility.

After a more detailed analysis I found out that the full-complex 
approach, while feasible is not fully backward compatible with the 
simple approach. The full-complex works nicely when the attribution 
context has an expected type (because the type inferred for diamond is 
compatible with the types inferred by both approaches). However, when
the attribution context is missing an expected type, things don't go as 
planned. Here's a simple example:

class Foo<X> {
 Foo<X>(X x) {}
 Foo<X> get() { return this; }
}

Foo<Object> = new Foo<>(1).get();

With the simple approach this works just fine. The argument type is 
never considered during inference - because of that, diamond ends up 
inferring Object (the bound of X) for X. Calling get() on a Foo<Object> 
yields a Foo<Object> which is compatible with the LHS type in the 
assignment.

Now suppose that in some release >7 we enable the full-complex approach. 
What would happen to this particular example? When a type is to be 
inferred for Foo<>, both argument and expected type are considered. Here 
there's no expected type (the LHS type of the assignment is the expected 
type for the get() call) - so full-complex is roughly equivalent to 
existing 15.12.2.7. Which (again) would yield a different type than the 
one returned by the simple approach - namely Foo<Integer> instead of 
Foo<Object>. Now, calling get() on Foo<Integer> would yield Foo<Integer> 
which is clearly incompatible with Foo<Object>. Btw: I'm not saying that 
accepting the above code is a must - an inference scheme can either 
accept (as simple) that or reject that (as complex); however, if we now 
choose a scheme that allows it, future releases will also have to cope 
with that, and we have seen clearly that even the full-complex approach 
cannot guarantee that.

Bottom line: the full-complex approach doesn't represent a viable 
alternative for reconciling the diamond inference routine with the 
standard javac's method inference routine - as a result, the simple 
approach currently implemented in the JDK7 would represent an obstacle 
for future language extensions. In principle, it would be possible to 
limit the scope of the simple approach to those contexts that have an 
expected type, so that the simple approach would fail when no expected 
type is given. While this is clearly a forward compatible solution, we 
believe it would be unnecessarily restrictive and ultimately not worth 
pursuing it.

Recalling from my earlier emails, the biggest disadvantage of the 
complex approach vs. simple is the following example:

Foo<Object> foo =  new  Foo<>(1);

However I believe this can eventually be fixed by an inference overhaul 
on the lines of the full-complex approach, so that the argument type 
inference would take into account the expected return type (thus 
inferring Object instead of Integer). Actually, that's also the biggest 
advantage of the complex approach: any change that will positively 
affect javac's standard type-inference, will positively affect diamond 
as a side-effect.

The next obvious step is to simply switch the diamond implementation in 
the jdk 7 repository, as we already have a working prototype (see [2]).

Thanks to everyone for participating in the discussion and helping in 
making Java a better language.
Maurizio

[1] - 
http://mail.openjdk.java.net/pipermail/coin-dev/2009-August/002165.html
[2] - http://cr.openjdk.java.net/~mcimadamore/6840638/webrev.1/




More information about the coin-dev mailing list