Reputation: 473
I am struggling to understand how a function type with receiver works in Kotlin. I don't understand why we can use (String) -> Unit and String.() -> Unit in my code indistinctively
fun main() {
var showStringFunction1: (String) -> Unit = ::showString
showStringFunction1("Hey")
var showStringFunction2: String.() -> Unit = ::showString
showStringFunction2("Hey")
}
fun showString(x: String): Unit { println(x) }
Upvotes: 2
Views: 1322
Reputation: 8096
Both the (String) -> Unit
and String.() -> Unit
are mapped to same JVM signature i.e. implementation of interface KFunciton1<String, Unit>
. That's why they behave the same.
The only difference you'll find is that when you are creating these you'll be presented with this
in case of String.() -> Unit
while any variable as of your choice in (String) -> Unit
.
While in case of referencing it is the same. However in Kotlin-1.4 I heard they are separating them (don't know if its true, will update answer if I confirm it).
Upvotes: 1
Reputation: 17691
Trying to reason about it the other way around:
String.() -> Unit
would be translated by Kotlin compiler to (String) -> Unit
, hence they are the same.
Using "Show Kotlin Bytecode"/"Decompile" you'll get the following result from both cases:
public final class AKt/BKt {
private static final void showString(String x) {
boolean var1 = false;
System.out.println(x);
}
public static final void main() {
Function1 showStringFunction2 = (Function1)null.INSTANCE;
showStringFunction2.invoke("Hey");
}
// $FF: synthetic method
public static void main(String[] var0) {
main();
}
}
Upvotes: 1
Reputation: 93551
The difference between these only matters when either:
You are passing a lambda. It affects whether the first parameter is this
or a named parameter inside the lambda. If you pass something other than a lambda, the receiver can be thought of as the first function argument.
You are invoking it. The receiver version is more versatile because you can also choose to invoke it like an extension function. But you can also invoke it as if the receiver is the first function argument.
A related concept comes when passing a function argument. So, showString
could be an extension fun String.showString(): Unit
and it could be passed to either of your variables in the example.
Upvotes: 3