Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does this Java 8 program not compile?

This program compiles fine in Java 7 (or in Java 8 with -source 7), but fails to compile with Java 8:

interface Iface<T> {} class Impl implements Iface<Impl> {}  class Acceptor<T extends Iface<T>> {     public Acceptor(T obj) {} }  public class Main {     public static void main(String[] args) {         Acceptor<?> acceptor = new Acceptor<>(new Impl());     } } 

Result:

Main.java:10: error: incompatible types: cannot infer type arguments for Acceptor<>         Acceptor<?> acceptor = new Acceptor<>(new Impl());                                            ^     reason: inference variable T has incompatible bounds       equality constraints: Impl       upper bounds: Iface<CAP#1>,Iface<T>   where T is a type-variable:     T extends Iface<T> declared in class Acceptor   where CAP#1 is a fresh type-variable:     CAP#1 extends Iface<CAP#1> from capture of ? 1 error 

In other words, this is a backwards source incompatibility between Java 7 and 8. I've gone through Incompatibilities between Java SE 8 and Java SE 7 list but did not found anything that would fit my problem.

So, is this a bug?

Environment:

$ /usr/lib/jvm/java-8-oracle/bin/java -version java version "1.8.0" Java(TM) SE Runtime Environment (build 1.8.0-b132) Java HotSpot(TM) 64-Bit Server VM (build 25.0-b70, mixed mode) 
like image 910
ghik Avatar asked Apr 14 '14 15:04

ghik


People also ask

Why is my Java file not compiling?

It means that javac.exe executable file, which exists in bin directory of JDK installation folder is not added to PATH environment variable. You need to add JAVA_HOME/bin folder in your machine's PATH to solve this error. You cannot compile and run Java program until your add Java into your system's PATH variable.

How do I fix compile errors in Java?

Java is very specific about use of characters such as semicolons, brackets, or braces. Forgetting a semicolon is the simplest of these errors, and is fixed by placing a semicolon at the end of the line which causes the error.

What is a compile error in Java?

Compile-time errors occur when there are syntactical issues present in application code, for example, missing semicolons or parentheses, misspelled keywords or usage of undeclared variables. These syntax errors are detected by the Java compiler at compile-time and an error message is displayed on the screen.


2 Answers

The Java Language Specification changed significantly regarding type inference. In JLS7, type inference was described in §15.12.2.7 and §15.12.2.8, whereas in JLS8, there is a whole chapter dedicated to Chapter 18. Type Inference.

The rules are quite complex, both in JLS7 and JLS8. It's difficult to tell the differences, but obviously there are differences, as is evident from section §18.5.2:

This inference strategy is different than the Java SE 7 Edition of The Java Language Specification [..].

However, the intention of the change was to be backwards compatible. See the last paragraph of section §18.5.2:

[..] The strategy allows for reasonable outcomes in typical use cases, and is backwards compatible with the algorithm in the Java SE 7 Edition of The Java Language Specification.

I can't tell whether that's true or not. However, there are some interesting variations of your code, that do not show the problem. For example, the following statement compiles without errors:

new Acceptor<>(new Impl()); 

In this case, there is no target type. That means the Class Instance Create Expression is not a poly expressions, and the rules for type inference are simpler. See §18.5.2:

If the invocation is not a poly expression, let the bound set B3 be the same as B2.

That's also the reason, why the following statement works.

Acceptor<?> acceptor = (Acceptor<?>) new Acceptor<>(new Impl()); 

Although there is a type in the context of the expression, it doesn't count as target type. If a class instance creation expression does not happen in either an assignment expression or an invocation expression, then it can't be a poly expression. See §15.9:

A class instance creation expression is a poly expression (§15.2) if it uses the diamond form for type arguments to the class, and it appears in an assignment context or an invocation context (§5.2, §5.3). Otherwise, it is a standalone expression.

Coming back to your statement. The relevant part of the JLS8 is again §18.5.2. However, I can't tell you if the following statement is correct according to the JLS8, of if the compiler is right with the error message. But at least, you got some alternatives and pointers for further information.

Acceptor<?> acceptor = new Acceptor<>(new Impl()); 
like image 126
nosid Avatar answered Oct 13 '22 00:10

nosid


Thanks for the report. This looks like a bug. I will take care of it and probably add a better answer once we have more information about why this is happening. I have filed this bug entry JDK-8043926, to track it.

like image 22
Vicente Romero Avatar answered Oct 12 '22 23:10

Vicente Romero