Showing posts with label default methods. Show all posts
Showing posts with label default methods. Show all posts

Thursday, 24 April 2025

Compatiblity between Kotlin and Java regarding Default Methods

In short, default methods in interfaces in Kotlin are not compatible with Java.

That's the short version.

The long version follows.

Let's have a simple Person interface written in Kotlin:

Now we wish to use it in Java.

This doesn't work. Although the interface defines a default implementation of getGender(), this default implementation is invisible when called from Java.

java: org.mrbear.kotlin.interfaces.MrBear is not abstract and does not override abstract method getGender() in org.mrbear.kotlin.interfaces.Person

Now, in the past there used to be something called @JvmDefault, but that is deprecated and doesn't work.

Instead it has been superseded by @JvmDefaultWithoutCompatibility1 and @JvmDefaultWithCompatibility2 (which, quite frankly, makes it a tad less understandable).

Also, when you use either annotation, you are required to add a command line parameter when you compile, or it won't work.

With compatibility requires -jvm-default=enable.

Without compatibility requires -jvm-default=no-compatibility.

However, it seems that the default is with compatibility that it is turned on automatically in Kotlin 2.2. Which will be released soonish hopefully.

How it works

Apparently what happens is that Kotlin automatically creates an Abstract class in the Interface that implements the methods that are default (under water). The abstract class is called Interface$DefaultImpls.

If you run Without Compatibility, it means that the DefaultImpls won't be generated but only "real Java default methods in the Interface". This means your interface in Kotlin will actually change (and is therefore not backwards compatible).

See reference [3] for more details.

References

[1] Kotlin LangRef - JvmDefaultWithoutCompatibility
https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.jvm/-jvm-default-without-compatibility/
[2] Kotlin LangRef - JvmDefaultWithCompatibility
https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.jvm/-jvm-default-with-compatibility/
[3] KT-4779 Generate default methods for implementations in interfaces
https://youtrack.jetbrains.com/issue/KT-4779/Generate-default-methods-for-implementations-in-interfaces

Thursday, 10 May 2018

Default method 'toString' overrides a member of 'java.lang.Object'

An interface "inherits" methods from the Object class. I wrote about this here1.

The quotes are appropriate, because Interfaces can only inherit from other Interfaces. An interface, when it does not have a super interface, declares all public non-final methods of the Object as members of the Interface (if not explicitly defined in the interface.

I recently attempted something like this TaxBracket2:

It doesn't work. In fact my IDE started complaining immediately with the following message.

Default method 'toString' overrides a member of 'java.lang.Object'

It is supposed to do that, so says the Java Language Spec3:

It is a compile-time error if a default method is override-equivalent with a non-private method of the class Object, because any class implementing the interface will inherit its own implementation of the method.

My colleague helpfully provided the alternative, which is to make an "elementString()" method in the Interface, which can be called in the toString() method of every Class that implements the Interface. (Further down in the JLS, this approach is almost word for word also given)

StackOverflow4 has a helpful link to the JDK mailinglist5 that explains it a lot more in depth.

One of the remarks that really struck a cord with me, is the fact that toString(), equals() and hashCode() are all basically related to the state of a Class, and do not belong in an Interface.

I have therefore decided to remove the offending default method.

References

[1] Do interfaces inherit from object class?
http://randomthoughtsonjavaprogramming.blogspot.nl/2017/07/do-interfaces-inherit-from-object-class.html
[2] Wikipedia - Tax bracket
https://en.wikipedia.org/wiki/Tax_bracket
[3] JLS 8 - 9.4.1.2. Requirements in Overriding
https://docs.oracle.com/javase/specs/jls/se8/html/jls-9.html#jls-9.4.3
[4] StackOverflow - Java8: Why is it forbidden to define a default method for a method from java.lang.Object?
https://stackoverflow.com/questions/24016962/java8-why-is-it-forbidden-to-define-a-default-method-for-a-method-from-java-lan
[5] Malinglist OpenJDK - Allow default methods to override Object's methods
http://mail.openjdk.java.net/pipermail/lambda-dev/2013-March/008435.html