BinaryCompatibleDefaultMethods

From APIDesign

(Difference between revisions)
Jump to: navigation, search
(New page: DefaultMethods are useful when one desperately needs to add a method into an existing '''interface'''. However, they decrease clarity of a ProviderAPI. As such, don't overuse. ...)
Line 1: Line 1:
-
[[DefaultMethods]] are useful when one desperately needs to add a method into an existing '''interface'''. However, they decrease [[clarity]] of a [[ProviderAPI]]. As such, don't overuse. Morever it has been recently demonstrated that adding [[DefaultMethods]] can even compromise [[BinaryCompatibility]].
+
[[DefaultMethods]] are useful when one desperately needs to add a method into an existing '''interface'''. However, they decrease [[clarity]] of a [[ProviderAPI]] (no, you [[DefaultMethods#Can_you_disagree.3F|can't disagree!]]). As such, don't overuse. Morever it has been recently demonstrated that adding [[DefaultMethods]] can even compromise [[BinaryCompatibility]]. Recently [https://twitter.com/emilianbold/status/1308677540408709125?s=20 Emilian Bold asked me] to participate in a tweeting about [[BinaryCompatible|binary incompatibility]] caused by adding '''CharSequence.isEmpty''' in JDK15. An interesting case. Following code compiles on JDK8 to JDK14:
-
 
+
-
 
+
-
Recently [https://twitter.com/emilianbold/status/1308677540408709125?s=20 Emilian Bold asked me] to participate in a tweeting about [[BinaryCompatible|binary incompatibility]] caused by adding '''CharSequence.isEmpty''' in JDK15. An interesting case. Following code compiles on JDK8 to JDK14:
+
<source lang="java">
<source lang="java">
-
public interface ArrayLike {
+
interface ArrayLike {
-
int length();
+
int length();
-
default boolean isEmpty() {
+
default boolean isEmpty() {
-
return length() == 0;
+
return length() == 0;
-
}
+
}
}
}
-
class CharArrayLike implements CharSequence, ArrayLike {
+
final class CharArrayLike implements CharSequence, ArrayLike {
-
private final char[] chars;
+
private final char[] chars;
 +
 
 +
CharArrayLike(char[] chars) {
 +
this.chars = chars;
 +
}
 +
 
 +
@Override
 +
public int length() {
 +
return chars.length;
 +
}
 +
 
 +
@Override
 +
public char charAt(int index) {
 +
return chars[index];
 +
}
 +
 
 +
@Override
 +
public CharSequence subSequence(int start, int end) {
 +
return new String(chars, start, end);
 +
}
 +
 
-
 
}
}
</source>
</source>
 +
 +
While the code compiles find with '''JDK14''' and older, it no longer compiles on '''JDK15'''. It results in:
 +
 +
<source lang="bash">
 +
$ /jdk-14/bin/javac ArrayLike.java
 +
$ /jdk-15/bin/javac ArrayLike.java
 +
ArrayLike.java:9: error: types CharSequence and ArrayLike are incompatible;
 +
final class CharArrayLike implements CharSequence, ArrayLike {
 +
^
 +
class CharArrayLike inherits unrelated defaults for isEmpty() from types CharSequence and ArrayLike
 +
1 error
 +
</source>
 +
 +
Why? Since '''JDK15''' there is '''CharSequence.isEmpty()''' [[DefaultMethods|default method]]. As such, when '''javac''' processes the '''CharArrayLike''' class it doesn't know whether to select the '''ArrayLike.isEmpty()''' or the newly added method.

Revision as of 06:20, 28 September 2020

DefaultMethods are useful when one desperately needs to add a method into an existing interface. However, they decrease clarity of a ProviderAPI (no, you can't disagree!). As such, don't overuse. Morever it has been recently demonstrated that adding DefaultMethods can even compromise BinaryCompatibility. Recently Emilian Bold asked me to participate in a tweeting about binary incompatibility caused by adding CharSequence.isEmpty in JDK15. An interesting case. Following code compiles on JDK8 to JDK14:

interface ArrayLike {
    int length();
 
    default boolean isEmpty() {
        return length() == 0;
    }
}
 
final class CharArrayLike implements CharSequence, ArrayLike {
    private final char[] chars;
 
    CharArrayLike(char[] chars) {
        this.chars = chars;
    }
 
    @Override
    public int length() {
        return chars.length;
    }
 
    @Override
    public char charAt(int index) {
        return chars[index];
    }
 
    @Override
    public CharSequence subSequence(int start, int end) {
        return new String(chars, start, end);
    }
 
 
}

While the code compiles find with JDK14 and older, it no longer compiles on JDK15. It results in:

$ /jdk-14/bin/javac ArrayLike.java 
$ /jdk-15/bin/javac ArrayLike.java 
ArrayLike.java:9: error: types CharSequence and ArrayLike are incompatible;
final class CharArrayLike implements CharSequence, ArrayLike {
      ^
  class CharArrayLike inherits unrelated defaults for isEmpty() from types CharSequence and ArrayLike
1 error

Why? Since JDK15 there is CharSequence.isEmpty() default method. As such, when javac processes the CharArrayLike class it doesn't know whether to select the ArrayLike.isEmpty() or the newly added method.

Personal tools
buy