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()}
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:
Calling this function would look like this:
There are a couple interesting things this language feature enabled:
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 theStringBuilder
type without having to call them on any instance.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.StringBuilder
- it could call it multiple times, on variousStringBuilder
instances, store it for later use, etc.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
.As you can see above, you call a lot of different methods on the
button
object, repeating the namebutton
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: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 useapply()
on any object even if it doesn't supportBuilder
pattern.The
apply()
function is defined in the Kotlin standard library as following (simplified):You can define your own lambdas with receivers in a similar fashion.