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)