Kotlin Function Literals with Receiver - The Foundation for DSLs and many Library Functions
Today I want to give a quick introduction to Kotlin Function Literals with Receiver. This concept is what makes Kotlin great for designing Domain Specific Languages as we know it from Groovy for example. Also, Kotlin's standard library includes many functions which many of you have already used or at least seen probably: apply
and with
are the most prominent ones.
Preconditions
Kotlin, other than Java, has proper function types, which means that variables can, for example, be of type "function accepting an Int
and returning a String
": (Int)->String
. These function types can be used as parameters to other functions, which are in turn called "higher order functions":
fun myHigherOrderFun(functionArg: (Int)->String) = functionArg(5)
As you can see myHigherOrderFun
has a parameter of a function type, which it can call in its method body. If we now want to use this higher order function, we can make use of lambdas, also referred to as "function literal":
println ( myHigherOrderFun { "The Number is $it" })
>> prints "The Number is 5"
Kotlin Function Literals with Receiver
As we've seen, function literals can be used as arguments to other functions, which is an awesome feature on its own. Nevertheless, Kotlin goes even further and supports the concept of "function literals with receivers". This enables us to call methods on the receiver of the function literal in its body without any specific qualifiers. This is very similar to extension functions, where it's also possible to access members of the receiver object inside the extension. Let's see, what function literals look like:
var greet: String.() -> Unit = { println("Hello $this") }
This one defines a variable of type String.() -> Unit
, which is basically a function type () -> Unit
with String
as the receiver. All methods of this receiver can, therefore, be called in the method body. In this example, this
is simply used to print the String
. The function can be called like so:
greet("Hadi")
>> prints "Hello Hadi"
This is essentially all you need to know, let's see a use case in action.
In Action - Scope Functions
As I already mentioned in the beginning, Kotlin's standard library contains methods using this concept, one of which is apply
. This one is defined as follows:
public inline fun <T> T.apply(block: T.() -> Unit): T { block(); return this }
As we can easily see, it's an extension function to everything literally, and it expects a function literal with a generic receiver of type T
, which is run before the receiver is returned to the caller. This little function is actually fantastic as it provides a way to build certain objects very concisely and easily.
println(StringBuilder("Hello ")
.apply {
append("Kotliner")
append("! ")
append("How are you doing?")
}.toString())
>> prints "Hello Kotliner! How are you doing?"
In this example, a StringBuilder
is created and then the apply
method is called on it. As we've seen before, it's possible to call any method of our receiver StringBuilder
like append
in the above code. Since apply
returns the receiver after it completes, a call of toString
on the StringBuilder
can immediately be performed and the text is printed to the console.
Hope this helps! I really like this feature because it gives us so many possibilities. Probably it's one of Kotlin's most important ones 🙂 If you want to learn about creating DSLs, have a look here. I myself found so many spots in my code, which I could simplify a lot using these receiver-aware functions; Have a look at yours today 😉
Finally, if you want to read about Kotlin's beautiful features I recommend the book Kotlin in Action to you!
Simon
Simon is a software engineer with 9+ years of experience developing software on multiple platforms including the JVM and Serverless environments. He currently builds scalable distributed services for a decision automation SaaS platform. Simon is a self-appointed Kotlin enthusiast.
[…] I already intimated in one of my last posts on Function Literals with Receiver, Kotlin is designed to enable the creation of great (internal) Domain Specific Languages. Besides […]
[…] that allow us to create those DSLs. One of these features, I also already introduced, is called Function Literals with Receiver, others are the invoke convention or infix […]
[…] The great thing is the usage of lambdas with receiver, which you can read about in one of my other posts. […]
[…] you might have wondered how they are implemented. The most relevant concept to understand is called function literal with receiver (also lambda with receiver). Since this feature is also vital for scope functions, it will be discussed […]
[…] I already intimated in one of my last posts on Function Literals with Receiver, Kotlin is designed to enable the creation of great (internal) Domain Specific Languages. Besides […]
You may want to fix your renderer — you have > showing up all over the place instead of >
Thx but I can’t see the error, is this still happening?
IMHO “Hadi”.greet() used to show function calling instead of greet(“Hadi”) helps in understanding better the point. Thanks for sharing indeed useful stuff.
[…] Lambdas with Receiver […]
Clear explanation but instead of greet(“Hadi”) you should use “Hadi”.greet() imho. Thanks anyway.