Default interface methods aren't considered abstract method implementations
Joseph D. Darcy
joe.darcy at oracle.com
Tue Feb 11 21:56:58 UTC 2025
Hi Attila,
FYI, some of the documentation for Project Lambda
https://openjdk.org/projects/lambda/
hints at the general design rationale here. For example, the default
methods (nee "defender methods") doc [1] discusses "favor classes over
interfaces" in method resolution and "if multiple methods from
interfaces, the user has to choose."
HTH,
-Joe
[1] https://cr.openjdk.org/~briangoetz/lambda/Defender%20Methods%20v4.pdf
On 2/10/2025 1:44 AM, Attila Szegedi wrote:
> Hi both Chen and Pavel,
>
> Thank you both for answering! I was not specifically asking Brian, of
> course, that’s why there’s a wink next to it :-)
> I now scoured JLS 23, specifically:
>
> ----
> 8.1.1.1. abstract Classes
>
> A class C has abstract methods if either of the following is true:
>
> Any of the member methods (§8.2) of C - either declared or inherited -
> is abstract.
>
> Any of C's superclasses has an abstract method declared with package
> access, and there exists no method that overrides the abstract method
> from C or from a superclass of C.
>
> 8.2. Class Members
>
> The members of a class are all of the following:
>
> Members inherited from its direct superclass type (§8.1.4), except in
> the class Object, which has no direct superclass type
>
> Members inherited from any direct superinterface types (§8.1.5)
>
> Members declared in the body of the class (§8.1.7)
>
> 8.1.5. Superinterfaces:
>
> Each default method (§9.4.3) of a superinterface of the class may
> optionally be overridden by a method in the class; if not, the default
> method is typically inherited and its behavior is as specified by its
> default body.
> -----
>
> And nothing in there tells me unambiguously that my example should’t
> work (the last quoted sentence from 8.1.1.1 is weird, but adding
> “public” to declaration of “m” circumvents it and it still doesn’t
> compile.) There are few phrases that seem open to interpretation
> though: "default method is _typically_ inherited” (typically is doing
> heavy lifting here: sometimes it isn’t?) and “_any of the member
> methods_ (§8.2) of C - either declared or inherited - is abstract"
> (are A.m() and F.m() treated as separate member methods at this stage
> despite identical signatures?)
>
> Again, I’m not arguing current javac behavior is wrong, just trying to
> understand why is it right. I actually hit this in an IRL refactoring
> – had several classes that both extended an abstract class (A) and
> implemented an interface (F), and all these classes had the same
> implementation for an abstract method (m) that was actually
> semantically related to F and it felt like a good example of DRY to
> implement the method only once as a default in F. (Yes, I could create
> an interim class AF and move the implementation there, but this felt
> like it would’ve been a good use of an interface as a mixin.)
>
> I wonder if I recreated the example in bytecode directly whether the
> JVM would load the class successfully (I might need to attempt to also
> call the method) or would I get some kind of IncompatibleClassChangeError.
>
> Attila.
>
> On 2025. Feb 10. at 1:58:32, Chen Liang <liangchenblue at gmail.com> wrote:
>> Hello guys, amber is for new language features. Questions with java
>> compilation or JLS/JVMS belong to the compiler group.
>>
>> That said, I believe this behavior is most likely a preservation of
>> method resolution, that for instance methods, methods from superclass
>> have higher priority than methods from interfaces. For example,
>> before Java 8, static methods could not be defined in interfaces; and
>> when they were added in 8, resolution rule states that they aren't
>> shadowed to child types, so classes cannot "inherit" interface static
>> methods, unlike interface static fields.
>>
>> Another fun fact is that superinterface fields take precedence in
>> resolution over superclass fields. Also a legacy from old Java, but I
>> don't think that is going to be changed to make things "consistent".
>>
>> Regards,
>> Chen Liang
>>
>> On Sun, Feb 9, 2025 at 4:26 PM Pavel Rappo <pavel.rappo at gmail.com> wrote:
>>
>> Attila,
>>
>> Come to think of it, we should use some other, more narrowly focused,
>> mailing list. Apologies to subscribers of this list. Since lambda-dev
>> is defunct now, perhaps we could use compiler-dev, amber-dev, or
>> core-libs-dev instead. I'm voting for amber-dev, where Brian mostly
>> resides these days.
>>
>> -Pavel
>>
>> On Sun, Feb 9, 2025 at 10:12 PM Pavel Rappo
>> <pavel.rappo at gmail.com> wrote:
>> >
>> > You are not specifically asking Brian, are you? If so, sorry
>> for replying.
>> >
>> > My humble take is that the default method is something to use when
>> > there's nothing else there. When there's something, even if it's
>> > abstract, we use that. So, a default method is a minimally
>> interfering
>> > fallback/extension scenario, if you will.
>> >
>> > That abstract A.m() effectively replaces default F.m() in C as if
>> > F.m() were never there. If F.m() were allowed to provide
>> > implementation for A.m() in C, then some uncompliable code could
>> > suddenly become compilable and operational at runtime.
>> >
>> > -Pavel.
>> >
>> > On Sun, Feb 9, 2025 at 9:04 PM Attila Szegedi
>> <szegedia at gmail.com> wrote:
>> > >
>> > > Hey folks,
>> > >
>> > > I found a somewhat puzzling behavior: default interface
>> methods aren't considered abstract method implementations. Trying
>> to compile this minimal reproducer:
>> > >
>> > > ------ C.java ------
>> > > abstract class A {
>> > > abstract void m();
>> > > }
>> > >
>> > > interface F {
>> > > default void m() {}
>> > > }
>> > >
>> > > class C extends A implements F {}
>> > > ------ C.java ------
>> > >
>> > > $ javac C.java
>> > > C.java:9: error: C is not abstract and does not override
>> abstract method m() in A
>> > > class C extends A implements F {
>> > > ^
>> > > 1 error
>> > >
>> > > I can accept this being valid according to JLS today (I tried
>> with 11, 21, and 23.) I admit this is one of rare occasions when
>> I didn't go scouring the JLS to figure out what exactly prevents
>> the compiler from accepting F.m() as implementation of A.m() in
>> C. I'm wondering though if this isn't something that could be
>> improved upon in the future. (I'm sure there's a gotcha
>> somewhere. Right, Brian? ;-) )
>> > >
>> > > Have a great day,
>> > > Attila.
>>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/compiler-dev/attachments/20250211/b793626d/attachment-0001.htm>
More information about the compiler-dev
mailing list