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