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