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

Joseph D. Darcy joe.darcy at oracle.com
Tue Apr 25 20:03:47 UTC 2023


On a related point, among the many advantages of using

     javac --release $OLD ...

over something like

     javac -source $OLD

is that whole categories of version mismatches, how newer language 
structures should be presented to older source versions, are avoided 
with respect to the platform libraries.

Compiling clients of libraries at -source/--release level no earlier 
than their dependencies seems like a reasonable build configuration 
constraint.

-Joe

On 4/25/2023 12:17 PM, Remi Forax wrote:
> ----- Original Message -----
>> From: "Alex Buckley" <alex.buckley at oracle.com>
>> To: "compiler-dev" <compiler-dev at openjdk.java.net>
>> Sent: Tuesday, April 25, 2023 7:09:41 PM
>> Subject: Re: 8306854: javac with '-source 7' should honor default methods in implemented Java 8 interfaces
>> 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
> Alex, Java 8 adds a lot of default methods to the interfaces of the collection API, so javac8 -source 7 could not stop each time it sees a default methods, otherwise a lot of code will never have compiled. Which means that javac7 -source 7 and javac8 -source 7 have to have different behaviors.
>
> It was decided that javac8 -source 7 should skip default methods because it works well with the collection API even if it does not work that well in other cases as the one provided by Volker.
>
> Volker, I believe the behavior you see is not a bug, it's how javac should behave. But i don't think this behavior is specified somewhere, that why ecj has a different behavior. Moreover, javac never behaves differently depending on a specific classfile version of a specific classfile to preserve the sanity of the people trying to debug issues involving several versions.
>
> regards,
> Rémi


More information about the compiler-dev mailing list