Java 8 language spec flaw/bug
Davin McCall
davmac at bluej.org
Thu Aug 21 16:18:35 UTC 2014
Hi,
Apologies if this is the wrong place for this.
I'm concerned with this bug:
https://bugs.openjdk.java.net/browse/JDK-8044053
It concerns changes in the language spec (and the compiler) that cause
some backwards incompatibility between Java 7 and Java 8. The example in
the bug ticket uses the trinary conditional operator but I believe this
is a red herring, that is, the same problem occurs when not using the
conditional operator. Specifically, the following compiles with Java 7
but not 8:
|--- begin ---
public class Foo {
public static void main(String[] args) throws Exception {
// compiles fine in Java 7 and Java 8:
Class<? extends CharSequence> aClass= ternary(true, String.class, StringBuilder.class);
CharSequence foo= foo(aClass);
// Inlining the variable using 'ternary' method
// Compiles with Java 7 but not with 8:
CharSequence foo2= foo(ternary(true, String.class, StringBuilder.class));
}
static <T> T foo(Class<T> clazz) throws Exception {
return clazz.newInstance();
}
static <T> T ternary(boolean cond, T a, T b) {
if (cond) return a;
else return b;
}
}
--- end ---
|
I'm worried about the comments in the bug, but I'm unable to make
comment myself (I don't have an OpenJDK account and it doesn't appear to
be possible for general members of the public to sign up). See Dan
Smith's comment:
> In general, the use of context provided by the new strategy is
> valuable, but in this case it interferes with the opportunity for
> capture. It might be possible to use a strategy similar to 18.5.2 in
> order to recognize situations in which eager bottom-up typing and
> capture is the more useful approach. Ultimately, this comes down to
> whether we consider the conditional expression to be a poly expression
> or not (see 15.25.3). (But changing the simple rule, "A reference
> conditional expression is a poly expression if it appears in an
> assignment context or an invocation context," to something more
> complex may not be worthwhile.)
This is, in my opinion, bogus. The problem is not in how conditional
expressions are treated at all - as I have demonstrated above, the
problem also occurs with generic methods. In fact the issue is with
section 18.2.3 of the JLS:
--- begin ---
18.2.3. Subtyping Constraints
...
A constraint formula of the form ‹S |<=| T›, where S and T are type
arguments (§4.5.1
<http://docs.oracle.com/javase/specs/jls/se8/html/jls-4.html#jls-4.5.1>),
is reduced as follows:
If T is a type:
* If S is a type, the constraint reduces to ‹S = T›.
--- end ---
This turns a 'contains' constraint directly into an 'equals' constraint,
which is precisely what causes the problem. I can see no justification
for this. It should instead imply a sub-type constraint, that is, it
should reduce to ‹S |<:| T›. At this point the problem goes away,
without - as far as I can see - having any negative impact on the
enhanced type inference that Java 8 provides. Instead of getting two
conflicting equality constraints for the T in the Foo example above
(T=String and T=StringBuilder), we would get two subtype constraints
(String <: T and StringBuilder <: T), which from a theoretical
perspective is perfectly correct.
Section 18.4 then details how to resolve the two constraints and applies
the lub function, just as would be done in the Java 7 language spec.
Am I crazy? It seems fundamentally obvious to me that a contains
constraint shouldn't be turned into an equality constraint, but everyone
else involved seems to be overlooking that. I'd appreciate if someone
can either set me straight, or add an appropriate comment to the ticket
at https://bugs.openjdk.java.net/browse/JDK-8044053. I'd hate to see
this getting "fixed" by changing "whether we consider the conditional
expression to be a poly expression or not".
Thanks,
Davin
More information about the lambda-dev
mailing list