Java 8 language spec flaw/bug

Davin McCall davmac at
Thu Aug 21 16:18:35 UTC 2014


Apologies if this is the wrong place for this.

I'm concerned with this bug:

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
    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 I'd hate to see 
this getting "fixed" by changing "whether we consider the conditional 
expression to be a poly expression or not".



More information about the lambda-dev mailing list