19

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?

Mibac
  • 8,990
  • 5
  • 33
  • 57
  • what do you get when your default parameters are last? as in `fun foo(bar: Int, baz: Int = 0) {} ` – Les Sep 03 '17 at 23:07
  • @Les just checked. It's the same (i.e. that weird Object var is generated) – Mibac Sep 03 '17 at 23:12
  • have you tried making a call, and see what is the object passed in the java code? – DPM Sep 04 '17 at 11:15
  • @DPM I've just done a basic test (`foo(baz = 2)`) and the passed parameter was `null`. I've edited the question too – Mibac Sep 04 '17 at 11:19
  • 1
    If you're asking this out of sheer curiosity, it's probably better to ask in Kotlin forums or Slack. If you want to call a Kotlin function with default parameters from Java, you should annotate it with `@JvmOverloads` annotation so the compiler generates clean overloaded methods with no magic parameters. – Strelok Sep 04 '17 at 21:37
  • I'm asking out of curiosity. I've already asked on slack but with no response. @Strelok – Mibac Sep 04 '17 at 21:38

1 Answers1

9

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);
      }
   }
}
fal
  • 2,997
  • 1
  • 22
  • 13