Difference between function type with receiver and extension function

Consider the following functions:

fun Int.ext() {
    // TODO
}

fun doSomething(f: Int.() -> Unit) {
    // TODO
}

The functional parameter f has the same type as the extension function ext. So, I can do this:

doSomething(Int::ext)

The question is…

In the body of doSomething function, I can do this:

fun doSomething(f: Int.() -> Unit) {
    42.f()    // OK
    f(42)     // OK
}

But when I call the ext function, this happens:

42.ext()    // OK
ext(42)     // compiler error

Why does that happens? I thought that function types with receivers were the same thing as extension function types, but now I’m not sure.

From the docs:

Non-literal values of function types with and without a receiver are interchangeable, so the receiver can stand in for the first parameter, and vice versa. For instance, a value of type (A, B) -> C can be passed or assigned where a value of type A.(B) -> C is expected, and the other way around:

val repeatFun: String.(Int) -> String = { times -> this.repeat(times) }
val twoParameters: (String, Int) -> String = repeatFun // OK

fun runTransformation(f: (String, Int) -> String): String {
   return f("hello", 3)
}
val result = runTransformation(repeatFun) // OK
1 Like

The syntax for calling an extension function on Int is not ext(42), it’s 42.ext().

If you first cast your Int.() → Unit function to (int) → Unit, as you do by calling your doSomething function, then you can do it. But not before.

Not true for values of function types. See above the code example form the docs