Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is a purpose of Lambda's with Receiver?

Tags:

What is a purpose of Lambda's with Receiver in Kotlin, while we have extension functions ?

Two functions below do the same things, however first one is more readable and short:

fun main(args: Array<String>) {
    println("123".represents(123))
    println(123.represents("123"))
}

fun String.represents(another: Int) = toIntOrNull() == another

val represents: Int.(String) -> Boolean = {this == it.toIntOrNull()}
like image 204
uptoyou Avatar asked Nov 16 '17 12:11

uptoyou


People also ask

What is lambda receiver?

A lambda with a receiver allows you to call methods of an object in the body of a lambda without any qualifiers. It is similar to the typed extension function but this time, for function types. The idea is similar to object initializers in C# but is extended to functions and in a declarative way.

What is receiver type in Kotlin?

It's called a receiver because you can think of the function call as sending a request which the object will receive. Not all functions have a receiver. For example, Kotlin's println() function is a top-level function. When you write: println("Hello, World!")

What is the use of lambda function in Kotlin?

Lambda expression is a simplified representation of a function. It can be passed as a parameter, stored in a variable or even returned as a value. Note: If you are new to Android app development or just getting started, you should get a head start from Kotlin for Android: An Introduction.

What is trailing lambda in Kotlin?

To help deal with this, Kotlin supports a specific kind of syntax referred to as trailing lambda syntax. This syntax states that if the final parameter to a function is another function, then the lambda can be passed outside of the function call parentheses.


2 Answers

Lambdas with receivers are basically exactly the same as extension functions, they're just able to be stored in properties, and passed around to functions. This question is essentially the same as "What's the purpose of lambdas when we have functions?". The answer is much the same as well - it allows you to quickly create anonymous extension functions anywhere in your code.

There are many good use cases for this (see DSLs in particular), but I'll give one simple example here.

For instance, let's say you have a function like this:

fun buildString(actions: StringBuilder.() -> Unit): String {
    val builder = StringBuilder()
    builder.actions()
    return builder.toString()
}

Calling this function would look like this:

val str = buildString {
    append("Hello")
    append(" ")
    append("world")
}

There are a couple interesting things this language feature enabled:

  • Inside the lambda you pass to buildString, you're in a new scope and as such have new methods and properties available for use. In this specific case, you can use methods on the StringBuilder type without having to call them on any instance.
  • The actual StringBuilder instance these function calls are going to be made on is not managed by you - it's up to the internal implementation of the function to create one and call your extension function on it.
  • Consequently, it would also be possible for this function to do much more than just call the lambda you passed to it once on one StringBuilder - it could call it multiple times, on various StringBuilder instances, store it for later use, etc.
like image 121
zsmb13 Avatar answered Sep 29 '22 14:09

zsmb13


Similarity

An extension function is, in a sense a function with a receiver. When you are using the lambdas with receiver, you are taking advantage of the extension functions feature of Kotlin.

A lambda is a way to define behavior similar to a regular function.

A lambda with a receiver is a way to define behavior similar to an extension function.

To understand the purpose of lambdas with receivers, consider the following example function that creates and returns a Button.

fun createButton(): Button {
    val button = Button()
    button.text = "Some text"
    button.height = 40
    button.width = 60
    button.setOnClickListener(listener)
    button.background = drawable
    return button
}

As you can see above, you call a lot of different methods on the button object, repeating the name button in every call. This is only a small example. It would be inconvenient and wouldn't look pretty, if the expression was longer or repeated many times.


Purpose

To make it more concise, pretty and more readable, we use a lambda with receriver using an extension function apply(). And refactor the above code like following:

fun createButton() = Button().apply {
    text = "Some text"
    height = 40
    width = 60
    setOnClickListener(listener)
    background = drawable
}

Now the code looks more pleasing to look at. The Button() is the receiver object and you can call the methods and set properties on it.

This is useful when you are creating an instance and initializing some properties instantly. In Java, this is done using the Builder pattern. In Kotlin, you can use apply() on any object even if it doesn't support Builder pattern.

The apply() function is defined in the Kotlin standard library as following (simplified):

fun <T> T.apply(block: T.() -> Unit): T {
    block()
    return this
}

You can define your own lambdas with receivers in a similar fashion.

like image 24
Yogesh Umesh Vaity Avatar answered Sep 29 '22 13:09

Yogesh Umesh Vaity