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)