diamond operator and non-denotable types
Maurizio Cimadamore
maurizio.cimadamore at oracle.com
Fri Apr 9 10:14:13 PDT 2010
Hi,
in the process of switching the implementation of the diamond algorithm
(following the discussion in [1]), we discovered a problem in the
specification of the diamond operator; more specifically, there are
cases in which diamond can end up inferring non-denotable types (see
below). Our proposed solution is to reject such cases, as the semantics
of instance creation expression involving non-denotable types is not
clear. Moreover, we have carried out additional benchmarks in order to
ensure that this restriction does not significantly alter the ease of
use of the diamond operator. The results, as you can read below, are
extremely positive.
As I said, there are two cases in which the diamond operator causes a
non-denotable type to be inferred in an instance creation expression:
*) intersection types in type-variable bounds:
EXAMPLE
class Foo<X extends Object & Serializable> {
...
}
Foo<?> foo = new Foo<>();
in this case the non-denotable type Foo<Object&Serializable> is inferred
for X.
*) captured types in constructor arguments
EXAMPLE
class Foo<X> {
Foo(X x) { ... }
}
Foo<? extends Integer> fi = ...
Foo<?> f = new Foo<>(fi);
In this case the non-denotable type Foo<Foo<#1>> is inferred for X
[where #1 <: Integer]
Despite attribution does not have problems with non-denotable types in
instance creation expressions, there are circumstances in which such
types cause problems in code generation --- this happens e.g. if a
non-denotable type is inferred in an anonymous class creation
expression; in this case the compiler will try to emit a classfile
Signature attribute for a non-denotable type, which is not allowed.
Moreover non-denotable types doesn't seem to comply with the set of
acceptable types in an instance creation expression (see JLS 15.9);
despite there's no explicit statement in the JLS forbidding e.g. an
intersection type as part of an instance creation expression, it seems
sensible to statically forbid these occurrence, as the semantics of such
types is not crystal clear --- these types are introduced as
compile-time artifacts in order to enhance the applicability of compiler
checks, but it is not clear what their behavior should look like.
The most straightforward solution (see above) is to issue an error when
a non-denotable type is returned as result of the diamond inference
scheme. In other words, I propose to change the current spec draft to
include a statement like:
"If the diamond algorithm infers a non-denotable type, an error must be
issued by the compiler".
I was worried that this spec change would have caused major
disruption in our diamond statistics, so I took some time in order to
re-run my diamond finder on the JDK... these are the results:
total instance creation expression: 5201
compatible types inferred with diamond: 4606 (88.56%)
non-denotable types: 0
incompatible types inferred with diamond: 595
non-denotable types: 1
In other words it seems like this spec change does not alter the
measurements we took sometime ago. In particular there is just one case
in which diamond yields a non-denotable type --- but in this case the
type is not compatible with the given assignment context (as such it
would have been rejected anyway).
I'd say this doesn't look bad at all, and that it has the obvious
advantage of fixing the spec problem discussed above. The proposed
changeset for the new diamond implementation can be found in [2] while
the changeset for reverting the current diamond implementation is given,
for completeness, in [3].
[1]
http://mail.openjdk.java.net/pipermail/coin-dev/2009-November/002393.html
[2] http://cr.openjdk.java.net/~mcimadamore/6939620/webrev.1/
[3] http://cr.openjdk.java.net/~mcimadamore/6939618/webrev.0/
Thanks
Maurizio
More information about the coin-dev
mailing list