Search code examples
kotlinthis

"this expression" in Kotlin


I know the meaning of "this expression" in almost language. But below code in Kotlin make total confuse:

fun <A, B, C> (A.(B) -> C).swap(): (B.(A) -> C) = { a: A -> // 1
    a.this@swap(this)
}

the interpret phrase for the function definition is that: "swap as a function that converts a function of type A.(B)->C in a function of type B.(A)->C , basically swapping the receivers of types A and B.

a.this is something i can not get. If just this in that place, i will understand the scope are belong to (A.(B) -> C).

a.this@swap is a monster now, and a.this@swap(this) is the brain explode.

is that true if i think a.this is "outside" of a, but if that is, i also do not get what it is. Sorry for my English.


Solution

  • The code as written is indeed very confusing and unreadable. To understand it, let's start with a function that turns a (A, B) -> C to a (B, A) -> C:

    fun <A, B, C> swap(f: (A, B) -> C): (B, A) -> C = { b, a ->
        f(a, b)
    }
    

    Hopefully this is straightforward enough to not need any explanation.

    Instead of (A, B) -> C and (B, A) -> C, let's change this function to work with A.(B) -> C and B.(A) -> C. These function types have a receiver. B.(A) -> C still takes two parameters B and A, but B is the receiver. This means that it is referred to as this inside a function of that type.

    So in the lambda, we remove the first parameter b (that's the receiver now), and refer to it using this.

    fun <A, B, C> swap(f: A.(B) -> C): B.(A) -> C = { a ->
        // here, "this" refers to the receiver of the returned function, of type B
        f(a, this)
    }
    

    Note that since f has A as the receiver, f(a, this) can be alternatively written as a.f(this). Let's do that instead:

    fun <A, B, C> swap(f: A.(B) -> C): B.(A) -> C = { a ->
        // same as f(a, this)
        a.f(this)
    }
    

    The functions we have written so far all take a parameter f. What if we made this parameter the receiver of swap? In other words, we write swap as an extension function of A.(B) -> C.

    Think about how you would refer to the receiver of swap inside the lambda you return. this inside the lambda would refer to the receiver of the returned B.(A) -> C, since that's the "closest" receiver. You would need to use a qualified this - this@swap.

    So we can replace f with this@swap, and we reach the code in the question:

    fun <A, B, C> (A.(B) -> C).swap(): B.(A) -> C = { a ->
        // this@swap refers to the receiver of swap
        // this refers to the receiver of the returned lambda i.e. an instance of B
        a.this@swap(this)
    }
    

    IMO, this@swap(a, this) is more readable.