2

I need some help understanding the following code as I am complete Kotlin newbie. This is from a kotlin post I found online

typealias genericContext<T> = Demo<T>.() -> Unit
class Demo<T> {
    infix fun doThis(block: genericContext<T>) = block()
    fun say(obj: T) = println(obj.toString())
}

fun main(args: Array<String>)
{
    val demo = Demo<String>()

    demo doThis { say("generic alias") }
}

So I understand that because of the infix we can skip the usual method call syntax i.e. demo.doThis and do demo doThis.
But I don't understand the following:
typealias genericContext<T> = Demo<T>.() -> Unit
This seems to associate the string genericContext<T> with something that looks like a lambda but I don't get the .() part. That extends Demo with a function ()? I am confused on how this works. Could someone shed some light?

Ruslan
  • 14,229
  • 8
  • 49
  • 67
Jim
  • 3,845
  • 3
  • 22
  • 47
  • Take a Look at [Function literals with receiver](https://stackoverflow.com/questions/54709311/typealias-and-extension-function-in-kotlin) – Igor Feb 15 '19 at 12:45
  • @ivw: That is a link to my post – Jim Feb 15 '19 at 13:50
  • The `ClassName.()` is the way to declare extension function. Exactly as the link above. Kotlin gives you a chance to create a (static) helper function that is possible to call as a member function (but it is only a syntactic sugar). There are lambda functions in Kotlin too (e.g.. () -> Unit). And it is possible to declare a type of lambda that has another type as the receiver (or `this` for short). Lambda with receivers is often used for DSLs and nice to read APIs in Kotlin. You call these lambdas as if they were methods in the code. The `typealias` is the shortcut, aka C #define – Eugene Petrenko Feb 15 '19 at 14:23

1 Answers1

4

typealias genericContext<T> = Demo<T>.() -> Unit is a type alias. It is simply giving a new name to the type on the right hand side. This means that declaration of doThis in Demo is equivalent to this:

infix fun doThis(block: Demo<T>.() -> Unit) = block()

Now for the type Demo<T>.() -> Unit: This is a function type. A function of this type takes a Demo as it's receiver argument, and returns Unit. It is therefore the type of all functions defined either in the Demo class or as an extension on the Demo class.

When you provide a lambda of this type (for example when you call the doThis function), then this will point to a Demo-object inside the lambda. For example:

someDemo.doThis {
    /* "this" is an object of type `Demo`.
     * In this case it's actually "someDemo", because the implementation of "doThis" 
     * calls "block" on the implicit "this".
     */
    this.say("Hey!")
}
marstran
  • 26,413
  • 5
  • 61
  • 67
  • I didn't understand `A function of this type takes a Demo as it's receiver,` Do you mean argument? So `()` symbolizes a function that takes `Demo` as argument and returns `Unit`? – Jim Feb 15 '19 at 13:51
  • Could you please elaborate that part? – Jim Feb 15 '19 at 14:15
  • @Jim The receiver is the object a method is called on. The receiver is bound to `this` in the function body. For example, when you call `"Hello world!".toUpperCase()`, then the string `"Hello world!"` is the receiver. – marstran Feb 15 '19 at 15:18