See this example code in Kotlin:
fun foo(bar: Int = 0, baz: Int) {
/* ... */
}
After decompiling it to Java code (Tools -> Kotlin -> Show Kotlin Bytecode -> Decompile) I got the following code
public static final void foo(int bar, int baz) {
}
// $FF: synthetic method
// $FF: bridge method
public static void foo$default(int var0, int var1, int var2, Object var3) {
if ((var2 & 1) != 0) {
var0 = 0;
}
foo(var0, var1);
}
I noticed that the resulting Java method has an unused Object var3
parameter.
I kind of thought that it may be related to functions in a class but when decompiling this code
class Foo {
fun foo(bar: Int = 0, baz: Int) {
/* ... */
}
}
I got this code
public final class Foo {
public final void foo(int bar, int baz) {
}
// $FF: synthetic method
// $FF: bridge method
public static void foo$default(Foo var0, int var1, int var2, int var3, Object var4) {
if ((var3 & 1) != 0) {
var1 = 0;
}
var0.foo(var1, var2);
}
}
As you can see the Object
parameter is still unused and just sits there.
Upon additional tests I noticed the same behavior for extension methods. The same goes when the default parameter is last (i.e. fun foo(bar: Int, baz: Int = 0) {}
)
I've also done a basic test to check what is that value set to when calling that function using the code below
fun main(args: Array<String>) {
foo(baz = 2)
}
And
class Something {
init {
foo(baz = 2)
}
}
After decompiling it I got the following code
public static final void main(@NotNull String[] args) {
Intrinsics.checkParameterIsNotNull(args, "args");
foo$default(0, 2, 1, (Object)null);
}
And
public final class Something {
public Something() {
FooKt.foo$default(0, 2, 1, (Object)null);
}
}
Which makes even less sense whatsoever.
My question is: Why does Kotlin generate an unused parameter for functions with default parameters? Is it a bug?
Kotlin Default Argument In Kotlin, you can provide default values to parameters in function definition. If the function is called with arguments passed, those arguments are used as parameters. However, if the function is called without passing argument(s), default arguments are used.
Default function parameters allow named parameters to be initialized with default values if no value or undefined is passed.
When no value is passed in the function definition, a default value is being set for the function definition, known as the default parameter. It allows the named parameters to get initialized with a default value when either undefined or no value is passed.
Only one parameter can be marked as vararg . If a vararg parameter is not the last one in the list, values for the subsequent parameters can be passed using named argument syntax, or, if the parameter has a function type, by passing a lambda outside the parentheses.
According to this, currently it's unused, but is reserved for adding super calls with defaults later.
You can see it in action here:
open class Foo {
open fun foo(bar: Int = 0, baz: Int) {
/* ... */
}
}
class Blah: Foo() {
override fun foo(bar: Int, baz: Int) {
}
}
which will generate a bytecode-to-Java Foo
of:
public class Foo {
public void foo(int bar, int baz) {
}
// $FF: synthetic method
// $FF: bridge method
public static void foo$default(Foo var0, int var1, int var2, int var3, Object var4) {
if(var4 != null) {
throw new UnsupportedOperationException("Super calls with default arguments not supported in this target, function: foo");
} else {
if((var3 & 1) != 0) {
var1 = 0;
}
var0.foo(var1, var2);
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With