Use of Scoping Functions in Kotlin

  1. Scope Functions in Kotlin
  2. Use Scope Functions in Kotlin
  3. Use the also Scope Function in Kotlin
  4. Use the let Scope Function in Kotlin
  5. Use the apply Scope Function in Kotlin
  6. Use the run Scope Function in Kotlin
  7. Use the with Scope Function in Kotlin

This article will discuss the scope function also in Kotlin. We will also go through the other scope functions available in Kotlin.

But first, let’s understand what scope functions are.

Scope Functions in Kotlin

Kotlin has many functions created solely to execute a piece of code in the context of an object. These functions are called the scope functions.

Scope functions create a temporary scope for the object when we call them with a lambda expression. There are 5 scope functions in Kotlin, namely, also, let, apply, run, and with.

While all the scope functions in Kotlin perform the same function, what’s different is how the object inside that block is available after the execution. Based on the return value and the object reference, we need to choose one of the five scope functions.

The table below shows each scope function’s object reference and return value.

Scope Function Object Reference Return Value Extension Function
also it Lambda Value It is an extension function.
let this Lambda Value It is an extension function.
apply - Lambda Value It is not an extension function.
run this Lambda Value It is not an extension function.
run this Context Object It is an extension function.
with it Context Object It is an extension function.

Use Scope Functions in Kotlin

The example below demonstrates the use of scope functions in Kotlin. In this code, we will use the let function to create the scope for the object Students.

data class Student(var firstName: String, var lastName: String, var age: Int, var address: String) {
    fun moving(newAddress: String) { address = newAddress }
    fun ageIncrease() { age++ }
}

fun main() {
    Student("David", "Miller", 24, "New York").let {
        println(it)
        it.moving("Chicago")
        it.ageIncrease()
        println(it)
    }
}

Output:

Use of Kotlin's scope functions

The scope function refers to the Student object as it in the output. Without using the scope function, we would have had to declare a new variable and initialize it with the Student object’s value to access it.

Use the also Scope Function in Kotlin

As mentioned in the table above, the also function in Kotlin provides a context object as an argument (it). We can use also when we need to perform actions that take the context object as the argument of any function.

Another great way to use also in Kotlin is when we require direct reference to the object itself and not its properties or function. Consider the example below to understand the also function in Kotlin.

fun main() {
    val numList = mutableListOf("one", "three", "five")
    numList
        .also { println("Elements in the list before adding a new one: $it") }
        .add("seven")
        println("Elements in the list after adding a new one: " + numList)
}

Output:

Use also Scope Function in Kotlin

Use the let Scope Function in Kotlin

The let scope function in Kotlin provides the context object as an argument it. Its return value is the result of the lambda execution.

We can use the let function to invoke multiple functions to accumulate results of call chains.

fun main() {
    val numList = mutableListOf("one", "three", "five", "seven", "nine")
    val resList = numList.map { it.length }.filter { it > 3 }
    println(resList)
}

Output:

[5,4,5,4]

Instead of using the resList in the example above, we can use the let scope function to print the lambda results.

fun main() {
    val numList = mutableListOf("one", "three", "five", "seven", "nine")
    numList.map { it.length }.filter { it > 3 }.let{
        println(it)
        //We can add more functions here
    }
}

Output:

[5,4,5,4]

If the code has only one function, we can replace the lambda (it) with the method reference symbol (::).

fun main() {
    val numList = mutableListOf("one", "three", "five", "seven", "nine")
    numList.map { it.length }.filter { it > 3 }.let(::println)
}

Output:

[5,4,5,4]

Use the apply Scope Function in Kotlin

When using the apply function in Kotlin (this), the context object is available as a receiver. We can use the apply function on blocks of code that do not have any return value.

The most common use case is during object configuration. Consider the below example where we create a Student object and then configure it.

data class Student(var Name: String, var age: Int = 0, var address: String = "")

fun main() {
    val david = Student("David Miller").apply {
        age = 24
        address = "New York"
    }
    println(david)
}

Output:

Use apply Scope Function in Kotlin

Use the run Scope Function in Kotlin

We get the context object as the receiver (this) while using the run function in Kotlin. The lambda execution result is itself the return value for this scope function.

The run function is most helpful when lambda has both object initialization and the return value’s computation.

class port(var url: String, var portNum: Int) {
    fun initialRequest(): String = "Initial default request"
    fun res(request: String): String = "This is the result of query '$request'"
}

fun main() {

    val portService = port("https://example.kotlinlang.org", 80)

    val finalResult = portService.run {
        portNum = 8080
        res(initialRequest() + " to port $portNum")
    }
    // the same code written with let() function:
    val letResult = portService.let {
        it.portNum = 8080
        it.res(it.initialRequest() + " to port ${it.portNum}")
    }
    println(finalResult)
    println(letResult)
}

Output:

Use run Scope Function in Kotlin

We can also use run in Kotlin as a non-extension function. This means that it will execute a statement block that requires expressions.

fun main() {
    val hexNum = run {
        val dig = "0-9"
        val hexDig = "A-Fa-f"
        val indication = "+-"
        Regex("[$indication]?[$dig$hexDig]+")
    }
    for (match in hexNum.findAll("+139 -ABFF 79")) {
        println(match.value)
    }
}

Output:

+139
-ABFF
79

Use the with Scope Function in Kotlin

The with function is also a non-extension function, like run. The thing with the with function is that it is passed as an argument but available as a receiver.

The with is best used for calling functions on the context object where we don’t want to provide the lambda results.

fun main() {
    val num = mutableListOf("one", "three", "five", "seven")
    with(num) {
        println("The function 'with' is called with argument $this")
        println("The function contains $size items")
    }
}

Output:

Use with Scope Function in Kotlin

Related Article - Kotlin Function

  • Kotlin flatMap() Function
  • Use of Inline Functions in Kotlin
  • Higher Order Functions in Kotlin