8306854: javac with '-source 7' should honor default methods in implemented Java 8 interfaces

Alex Buckley alex.buckley at oracle.com
Tue Apr 25 17:09:41 UTC 2023


On 4/25/2023 8:33 AM, Volker Simonis wrote:
> ```
> interface A {
>    void foo();
> }
> ```
> 
> ```
> interface B extends A {
>    @Override default void foo() { }
> }
> ```
> 
> ```
> class C implements B { }
> ```
> 
> If we compile `A.java` and `B.java` with `javac -source 8` and
> `C.java` with `-source 7` we will get the following error:
> ```
> $ javac -source 8 A.java
> $ javac -source 8 B.java
> $ javac -source 7 C.java
> C.java:1: error: C is not abstract and does not override abstract
> method foo() in A
> class C implements B { }
> ```
> 
> I think this is wrong, because `foo()` is implemented as a default
> method in `B`.

The Java language circa JLS7 does not have default methods, so the 
membership of C cannot possibly involve a default method inherited from 
B. The Java language is backward compatible, not forward compatible.

A Java compiler that adheres to JLS7 (`-source 7`) is right to reject 
C.java -- either with the error given above, or with a more 
context-aware error along the lines of "C is written for Java 7, cannot 
inherit default method from B".

> The following, slightly simpler example works perfectly fine, although
> it also depends on a default method in an implemented interface:
> 
> ```
> interface D {
>    default void bar() { }
> }
> ```
> 
> ```
> class E implements D { }
> ```
> 
> ```
> $ javac -source 8 D.java
> $ javac -source 7 E.java
> ```
> 
> In the second example, `javac` happily accepts the default
> implementation of `bar()` from interface `D`.

It's hard to see how javac is processing class E, so I added a method 
declaration `@Override public void bar() {}` to E and `javac -source 7 
E.java` accepted the code. That's improper, because in Java 7 there is 
no such thing as a default method in D to override from E.

I then added a method invocation `D.super.bar();` as the body of E's bar 
method. In JLS8, this means "invoke my superinterface's default method". 
However, in JLS7, it means "invoke my enclosing class's method", but D 
isn't an enclosing class, so it's illegal (see 
https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.12.1-100-D) 
-- yet `javac -source 7 E.java` accepts it anyway. Highly improper on 
javac's part.

Alex


More information about the compiler-dev mailing list