Scope functions

Kotlin provides several standard functions whose sole purpose is to execute a block of code in the context of an object. Most of them implemented as extension method.

Main difference between these functions are

  1. how you can refer to the object within block: via the this keyword or via a local variable with the default name it
  2. return type of block: object itself or last value within block
/* Replace following code
val worker = Person()
worker.firstName = "John"
worker.lastName = "Smith"
...
return worker
*/
return Person().apply{
    firstName = "John" // same as this.firstName = "John" 
    lastName = "Smith" 
    ...
}
function description
apply{} Calls the specified function block and return object itself. Use the this keyword to refer to the object within block. Implemented as extension method.
also{} Calls the specified function block and return object itself. Use the it variable to refer to the object within block. Implemented as extension method.
run{} Calls the specified function block and returns its result. Use the this keyword to refer to the object within block. Implemented as extension method.
let{} Calls the specified function block and returns its result. Use the it variable to refer to the object within block. Implemented as extension method.
with(obj){} Calls the specified function block and returns its result. Use the this keyword to refer to the obj within block.
takeIf{} Returns object itself if object satisfies the given predicate or null, if it doesn't. Use the it variable to refer to the object within the predicate block. Implemented as extension method.
takeUnless{} Returns object itself if object does not satisfy the given predicate or null, if it does. Use the it variable to refer to the object within the predicate block. Implemented as extension method.

examples

/* Replace following code
val worker = Person()
worker.firstName = "John"
worker.lastName = "Smith"
...
return isAllOk(worker)
*/
return Person().run{
    firstName = "John" // same as this.firstName = "John" 
    lastName = "Smith" 
    ...
    isAllOk(worker)
}
class MyCls { ... fun assignJob() { myJob?.also{ // it refer to the myJob it.sallary = 3000 it.addWorker(Person().apply{ firstName = "John" lastName = "Smith" mainJob = it // nested blocks allowed ... this@MyCls.doSomething() // call method of MyCls }) ... } ?: // do something if myJob is null }
Department.getJob("jobname")?.also{ job -> // rename default it to the job job.sallary = 3000 ... }
val number = Random.nextInt(100) val evenOrNull = number.takeIf { it % 2 == 0 } val oddOrNull = number.takeUnless { it % 2 == 0 }