thecodex.expert · The Codex Family of Knowledge
Kotlin

Scope Functions

apply and also do almost the same thing syntactically — the entire difference is whether you refer to the object as this or it inside the lambda, and picking the wrong one is a common source of confusion.

Kotlin 2.1 Differ by receiver + return value Last verified:
Canonical Definition

All five scope functions run a lambda against a given object, but vary along exactly two independent axes. Reference style: let and also refer to the object as it (useful when you want a short, explicit name, or need to pass it elsewhere); run, with, and apply refer to it as this (letting you call the object's own members directly, without a prefix). Return value: let, run, and with return the LAMBDA's result; apply and also return the ORIGINAL OBJECT itself, which is why apply is the idiomatic choice for configuring an object and then continuing to use that same object afterward.

let: null-checks and returning a transformed result

let is idiomatic specifically for running code only when a nullable value isn't null, and for producing a NEW, transformed result from the lambda — here, length is the lambda's return value, not name itself.

Kotlinlet_example.kt
val name: String? = "Alice"

val length = name?.let {
    println("Name is $it")   // 'it' — the object itself
    it.length                  // the LAMBDA's result becomes let's return value
}
println(length)   // 5

apply: configure an object, then keep using THAT object

apply returns the ORIGINAL person object itself, not the lambda's result — exactly why it's idiomatic for object configuration, letting the whole expression still evaluate to the object being configured.

Kotlinapply_example.kt
class Person { var name: String = ""; var age: Int = 0 }

val person = Person().apply {
    name = "Alice"   // 'this' — implicit, calling the object's own members directly
    age = 30
}   // apply returns the ORIGINAL Person object, now configured

println(person.name)   // "Alice"

also: a side-effect step, without changing the value

also returns the SAME object let received (like apply), but refers to it as it (like let) — idiomatic for a quick side effect, like logging, inserted into the middle of a chain of calls without disrupting the chain.

Kotlinalso_example.kt
val numbers = mutableListOf(1, 2, 3)
    .also { println("Original list: $it") }   // side effect — logging, doesn't change the list
    .apply { add(4) }                             // configure/mutate, returns the list itself

println(numbers)   // [1, 2, 3, 4]

Sources

1
JetBrains. Kotlin Documentation, "Scope functions," kotlinlang.org/docs/scope-functions.html.