DEV Community

Frevib
Frevib

Posted on

Kotlin extension function vs function literal with receiver

Kotlin extension function and function literal with receiver

In Kotlin it is possible to add a method (called member function in Kotlin) to an existing class. This is called an extension function.

It is also possible to access a member function from a class inside a function literal. This is called a function literal with receiver.

Extension function

Say you want to add a new member function to the StringBuilder class, e.g. appendMonkey() that appends the string β€œmonkey” to a string. Because StringBuilder is in the Java SDK, we cannot modify it. In Kotlin we can define an extension function that extends an existing class like StringBuilder with a new member function.

We define the appendMonkey() extension function as follows:

fun StringBuilder.appendMonkey(): StringBuilder = this.append("monkey")

this refers to the StringBuilder object, and we can omit it:

fun StringBuilder.appendMonkey(): StringBuilder = append("monkey")

Full example:

import java.lang.StringBuilder

fun main() {
    val sb = StringBuilder()

    sb.append("Hello extension function ")
    sb.appendMonkey()

    println(sb.toString())
}

fun StringBuilder.appendMonkey(): StringBuilder = append("monkey")

Function literal with receiver

Closely related to the extension function is the function literal with receiver. There are two types of function literals:

  • lambda
  • anonymous function

In practice you will most likely use the lambda expression, so we use that in the example below.

Where with extension functions you can add a new member function to an existing class, with a function literal with receiver you can access the member functions of an existing class inside the lambda block (inside the curly braces {}).

Let's create a function literal with receiver that adds the string "monkey" to a string using the StringBuilder class.

val lambdaAppendMonkey: StringBuilder.() -> StringBuilder = { this.append("monkey") }

Again, this refers to the StringBuilder object, so we omit it:

val lambdaAppendMonkey: StringBuilder.() -> StringBuilder = { append("monkey") }

Full example:

 import java.lang.StringBuilder

fun main() {
    val lambdaAppendMonkey: StringBuilder.() -> StringBuilder = { append("monkey") }

    val sb = StringBuilder()
    sb.append("Hello lambda ")

    println(lambdaAppendMonkey(sb).toString())
}

Here, inside the block of the lambda we can access the append() member function because we explicitly stated the return type to be StringBuilder.() -> StringBuilder. This return type basically says:

"return a function that takes no arguments and returns a StringBuilder object, and give this function access to the StringBuilder member functions".

Good luck!

Top comments (0)