DEV Community

Tuhin Chakraborty
Tuhin Chakraborty

Posted on

Kotlin Scope Functions

Scope Functions

run, with, let, apply, also


First things first, They are higher order functions

But... What are higher order functions anyways

On a very basic level they execute a function which is supplied to it. The Kotlin standard library is full of higher order functions. One of them being repeat.

    public inline fun repeat(times: Int, action: (Int) -> Unit)

The repeat function takes an action as an argument and returns Unit, but a higher order function can return any object. If you would want to invoke repeat, you would have to pass a function to this which will be invoked by the repeat function.
e.g.

    repeat(3) {
        println("current value $it")
    }

If you would want to write my very own higher order repeat function you can follow the same syntax.

    fun <T> T.myFunction(action: (T) -> String) {
        ...
    }

So, with that knowledge we can approach scope functions knowing they are higher order functions provided by the Kotlin standard library just like repeat.

  • run Takes an expression which is a piece of code, and executes it. This may or may not return a value. The whole idea of the run scope function is to run a piece of code.
    data class Person(
        var name: String,
        var age: Int,
        var job: String
    ) {
        fun printPerson() = println(this)
    }

    val john = Person("John Doe", 20, "Plumber")
    val jane = Person("Jane Doe", 20, "Waitress")

    john.run {
        if (age > jane.age) println("John")
    }

    john.run {
        if (age > jane.age) this else jane
    }.printPerson()

    run {
        if (john.age > jane.age) john else jane
    }.printPerson()

  • with Exactly the same as run, the only difference being it takes a receiver as an input. It is the same as calling run with an object instead of an argument.
    with(john) { // similar to the run function being called with the object
            age += 1
            "Age is $age"
        }.printThis()
  • let let takes a 'this' value and performs operations on it (see what I did there..) and may or may not return a value.
    john?.let {
            it.age += 1
            "Age is ${it.age}"
        }.printThis() ?: defaultValue()

let is most useful when used with Kotlin's null checks. This allows you to execute a piece of code only when an object exists.

  • apply It takes an object argument and returns the same object. It is very useful when we are transforming the object.
    jane.apply {
        jane.age = 22
        jane.job = "Restaurant Owner"
    }.printPerson()

Another use case of apply is to initialize objects. In the below case the property name can be lazily initialized or transformed using apply.

    val apply = Planet().apply {
        name = "Earth"
    }
  • also Is similar to apply, the only difference being it receives a lambda which is accessed within the lambda with a name.
   val apply = Planet().also {
        it.name = "Earth"
    } 

Top comments (0)