Learning -Xjvm-default=all and Xjvm-default=all-compatibility in Kotlin

tommykw

Kenji Tomita

Posted on July 19, 2020

Learning -Xjvm-default=all and Xjvm-default=all-compatibility in Kotlin

Introduced on the official Kotlin blog about generating default methods in interfaces. -Xjvm-default=all, -Xjvm-default=all-compatibility options are avaiable in Kotlin 1.4. To use advantage of these, you need to target Java 8, which allows you to generate methods in your interface by default. Let's try it.

Try using -Xjvm-default=all

The following code is the sample code. Define sleep() in the Animal interface. The Dog class inherits the Animal interface and calls Dog().sleep() in main().

// Main.kt 

fun main() {
    Dog().sleep()
}

class Dog : Animal

interface Animal {
    fun sleep() {
        println("The animal sleeps.")
    }
}
Enter fullscreen mode Exit fullscreen mode

This time, I'm using IntelliJ IDEA, which allows you to easily reference the bytecode of Kotlin code and decompile it. For the procedure, select Tools -> Kotlin -> Show Kotlin Bytecode.

Alt Text

Then, the bytecode is displayed, so if you click the Decompile button, it will be decompiled.

Alt Text

So far, I have introduced the decompilation procedure. Let's set the -Xjvm-default=all option. Select IntelliJ IDEA -> Preferences -> Build, Execution, Deployment -> Compiler -> Kotlin Compiler. Select Language version and API version to 1.4, set -Xjvm-default=all to Additional command line parameters, and finally set Target JVM version to 1.8.

Alt Text

Now let's decompile. The following code is the decompiled code.

// MainKt.java
import kotlin.Metadata;

@Metadata(
   mv = {1, 4, 0},
   bv = {1, 0, 3},
   k = 2,
   xi = 2,
   d1 = {"\u0000\b\n\u0000\n\u0002\u0010\u0002\n\u0000\u001a\u0006\u0010\u0000\u001a\u00020\u0001¨\u0006\u0002"},
   d2 = {"main", "", "algo"}
)
public final class MainKt {
   public static final void main() {
      (new Dog()).sleep();
   }

   // $FF: synthetic method
   public static void main(String[] var0) {
      main();
   }
}
// Dog.java
import kotlin.Metadata;

@Metadata(
   mv = {1, 4, 0},
   bv = {1, 0, 3},
   k = 1,
   xi = 2,
   d1 = {"\u0000\f\n\u0002\u0018\u0002\n\u0002\u0018\u0002\n\u0002\b\u0002\u0018\u00002\u00020\u0001B\u0005¢\u0006\u0002\u0010\u0002¨\u0006\u0003"},
   d2 = {"LDog;", "LAnimal;", "()V", "algo"}
)
public final class Dog implements Animal {
}
// Animal.java
import kotlin.Metadata;

@Metadata(
   mv = {1, 4, 0},
   bv = {1, 0, 3},
   k = 1,
   xi = 2,
   d1 = {"\u0000\u0010\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0000\n\u0002\u0010\u0002\n\u0000\bf\u0018\u00002\u00020\u0001J\b\u0010\u0002\u001a\u00020\u0003H\u0016ø\u0001\u0000\u0082\u0002\u0006\n\u0004\b!0\u0001¨\u0006\u0004À\u0006\u0001"},
   d2 = {"LAnimal;", "", "sleep", "", "algo"}
)
public interface Animal {
   default void sleep() {
      String var1 = "The animal sleeps.";
      boolean var2 = false;
      System.out.println(var1);
   }
}
Enter fullscreen mode Exit fullscreen mode

As you can see, default is set in sleep() of the Animal interface.

Try using -Xjvm-default=all-compatibility

Let's use -Xjvm-default=all-compatibility. Change -Xjvm-default=all-compatibility to Additional command line parameters.

Alt Text

Let's decompile.

// MainKt.java
import kotlin.Metadata;

@Metadata(
   mv = {1, 4, 0},
   bv = {1, 0, 3},
   k = 2,
   xi = 2,
   d1 = {"\u0000\b\n\u0000\n\u0002\u0010\u0002\n\u0000\u001a\u0006\u0010\u0000\u001a\u00020\u0001¨\u0006\u0002"},
   d2 = {"main", "", "algo"}
)
public final class MainKt {
   public static final void main() {
      (new Dog()).sleep();
   }

   // $FF: synthetic method
   public static void main(String[] var0) {
      main();
   }
}
// Dog.java
import kotlin.Metadata;

@Metadata(
   mv = {1, 4, 0},
   bv = {1, 0, 3},
   k = 1,
   xi = 2,
   d1 = {"\u0000\f\n\u0002\u0018\u0002\n\u0002\u0018\u0002\n\u0002\b\u0002\u0018\u00002\u00020\u0001B\u0005¢\u0006\u0002\u0010\u0002¨\u0006\u0003"},
   d2 = {"LDog;", "LAnimal;", "()V", "algo"}
)
public final class Dog implements Animal {
}
// Animal.java
import kotlin.Metadata;
import org.jetbrains.annotations.NotNull;

@Metadata(
   mv = {1, 4, 0},
   bv = {1, 0, 3},
   k = 1,
   xi = 2,
   d1 = {"\u0000\u0010\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0000\n\u0002\u0010\u0002\n\u0000\bf\u0018\u00002\u00020\u0001J\b\u0010\u0002\u001a\u00020\u0003H\u0016¨\u0006\u0004À\u0006\u0001"},
   d2 = {"LAnimal;", "", "sleep", "", "algo"}
)
public interface Animal {
   default void sleep() {
      String var1 = "The animal sleeps.";
      boolean var2 = false;
      System.out.println(var1);
   }

   @Metadata(
      mv = {1, 4, 0},
      bv = {1, 0, 3},
      k = 3,
      xi = 2
   )
   public static final class DefaultImpls {
      public static void sleep(@NotNull Animal $this) {
         $this.sleep();
      }
   }
}
Enter fullscreen mode Exit fullscreen mode

default is set for sleep() of the Animal interface. You can also see that the DefaultImpls are generated. This time, I introduced how to use each option. For more details, please refer to Kotlin official blog.

💖 💪 🙅 🚩
tommykw
Kenji Tomita

Posted on July 19, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related