How Kotlin supports default function parameters when Java does not

Joao Foltran
CodeX
Published in
2 min readJul 28, 2022

You have probably already used Kotlin’s default function parameters to simplify function calls and encapsulate default behavior. However, Java does not provide this support. Yet, both languages are interoperable and Kotlin code even gets compiled to Java bytecode, when targeting Kotlin/JVM. This article helps you understand how Kotlin bridges the gap between supporting default parameters, yet remaining interoperable with Java. Let’s get going!

image by TimHill

What is meant by interoperability?

In this article we discuss Kotlin’s interoperability with Java, that is, when Kotlin is compiled to target Kotlin/JVM. In a nutshell,

Kotlin and Java files can exist in the same project and can directly communicate with each other. You may call Java methods from Kotlin and Kotlin functions from Java. Similarly, you may use Java’s APIs and frameworks in Kotlin and vice-versa.

Default parameters’ (lack of) interoperability

Let’s take a look at what happens behind the scenes when we compile a Kotlin function with default parameters.

Decompiling the bytecode to Java, we get this (simplified for clarity) definition of sample that does not support any default parameters:

Notice that the Kotlin version of sample can be called in four different ways:

Yet, the more verbose Java version can only be called if all two arguments are explicitly passed. That is, when calling the Kotlin function from a Java file we’d get:

Default parameters’ (better) interoperability

To provide better interoperability with Java in more specific cases, JVM provides several annotations to instruct the compiler how to compile the Kotlin code. For example, the @JvmOverloads annotation

instructs the Kotlin compiler to generate overloads for a given function that substitute default parameter values.

In practice, this means that by adding the @JvmOverloads annotation to your Kotlin function, you ask the Kotlin compiler to try to reproduce the default parameter behavior by overloading the method in different ways. For example:

Now decompiles to the following method overloads. For simplicity we abstract Java’s implementation logic that uses synthetic methods.

In practice, this means that we can now call from Java, with no errors:

Limitations

Great, we learned that by using method overloading, Java is able to provide a better interoperability with Kotlin’s default parameter functions. But you might have noticed that there’s still one missing case in the example above. What if we would like to call sample with its default a parameter and a custom b?

This is possible in Kotlin, since it supports named arguments, but it is not supported in Java. Since parameters a and b are both of type String , method overloading is not able to differentiate between them, so we are not able to replicate the call above in Java.

Thanks for reading! If you like the content, don’t forget to clap and follow for more!

--

--