Understand Kotlin Function Literal with Receiver by Example

This article provides some simple code examples of using function literal with receiver (also known as lambda/anonymous function with receiver).

Understand Kotlin Function Literal with Receiver by Example

I came across this lambda syntax - NavGraphBuilder.() -> Unit and it turns out it is called Function Literal with Receiver, which is also known as Lambda/Anonymous Function with Receiver.

The syntax looks like this:

Receiver.(Parameters) → ReturnType

The following shows some examples of building a custom string using function literal with receiver.

Example 1: Function Literal With Receiver

fun buildCustomStringExample1(
    action: StringBuilder.(String) -> Unit): String {

    val stringBuilder = StringBuilder()
    stringBuilder.action("Example1")
    return stringBuilder.toString()
}

action is the function literal / lambda function with receiver. StringBuilder is the receiver. It acts like an extension function of StringBuilder which takes in the string as input parameter.

To call action, StringBuilder is instantiated, call it like an extension function - stringBuilder.action("Example1")

You can imagine action is like a callback function that belongs to StringBuilder.

Usage

This is the usage of function literal with receiver:

val output1 = buildCustomStringExample1 { content ->
    this.append("<tag>")
    append("$content") 
    append("</tag>")
}
println("$output1")

We call the buildCustomStringExample1 with function literal / lambda function parameter. In this lambda function, we specify how we build the custom string - wrap the content with "<tag>" and "</tag>".

content is the input parameter which is passed in from the buildCustomStringExample1 function. this is the StringBuilder instance that created in buildCustomStringExample1() function, and it can be omitted. append() is the function that belongs to StringBuilder.

[Updated - Jun 12, 22]: I recently learned that this type of usage is called domain-specify language (DSL). So, function literal with receiver is used to build DSL. The main purpose is for readability.

Output

The output looks like this:

<tag>Example1</tag>

Example 2: Function Literal Without Receiver

Function literal / lambda function with receiver can be rewritten without using the receiver based on the following syntax:

(Receiver, Parameters) → ReturnType

This is the usual lambda expressions which takes in 2 parameters. The first parameter is, StringBuilder which is the receiver in example 1 above.

fun buildCustomStringExample2(
    action: (StringBuilder, String) -> Unit
): String {

    val stringBuilder = StringBuilder()
    action(stringBuilder, "Example2")
    return stringBuilder.toString()
}

action is the usual callback function which takes in 2 parameters. To call action, StringBuilder is instantiated, and passed in as the first parameter of the action callback function - action(stringBuilder, "Example2")

Usage

This is the usage of function literal without receiver:

val output2 = buildCustomStringExample2 { stringBuilder, content ->
    stringBuilder.append("<tag>")
    stringBuilder.append("$content")
    stringBuilder.append("</tag>")
}
println("$output2")

This is similar to example 1 except we no longer use this which has been replaced by stringBuilder as the first lambda parameter. content is the second parameter of the lambda function.

Output

The output looks like this, which has the same output as example 1:

<tag>Example2</tag>

Conclusion

It is not hard to understand function literal with receiver. It is basically a simplified way to write normal function literal / lambda function without additional parameter.

Function Literal with Receiver can be rewritten as Function Literal without Receiver.

Receiver.(Parameters) → ReturnType ---> (Receiver, Parameters) → ReturnType

Did you find this article valuable?

Support Vincent Tsen - AndroidDev Blog by becoming a sponsor. Any amount is appreciated!