20

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?

6
  • what do you get when your default parameters are last? as in fun foo(bar: Int, baz: Int = 0) {} Commented Sep 3, 2017 at 23:07
  • @Les just checked. It's the same (i.e. that weird Object var is generated) Commented Sep 3, 2017 at 23:12
  • have you tried making a call, and see what is the object passed in the java code? Commented Sep 4, 2017 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 Commented Sep 4, 2017 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. Commented Sep 4, 2017 at 21:37

1 Answer 1

10

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);
      }
   }
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.