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