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)