Skip to content

/compare/kotlin/let-vs-apply-vs-also-vs-run

Kotlin let vs apply vs also vs run vs with: scope functions compared

The commands on this page have not been executed by our verification runner yet.updated
tool
Kotlin
compares
let / also vs apply / run / with

Kotlin's five scope functions all run a block on an object; they differ in how the block refers to the object (it or this) and what they return (the object itself or the block's result). let (it, returns the result) is for null checks and transforming a value; apply (this, returns the object) configures an object; also (it, returns the object) adds side effects such as logging; run (this, returns the result) computes a value from an object; with(obj) is run called as a normal function.

The table to remember

FunctionObject inside the blockReturnsTypical use
letitBlock resultx?.let { ... } null checks, mapping a value
alsoitThe objectSide effects: logging, validation, adding to a list
applythisThe objectConfiguring an object (builder style)
runthisBlock resultComputing a result from an object; also run { } without receiver
with(obj)thisBlock resultCalling several members of an object; not an extension

Examples

kotlin
data class User(var name: String, var email: String? = null)

// let: run only when non-null, return the result
val length = readlnOrNull()?.let { it.trim().length } ?: 0

// apply: configure and return the same object
val user = User("ada").apply {
    email = "ada@example.com"
}

// also: side effect, the object passes through unchanged
val saved = user.also { println("saving ${it.name}") }

// run: compute a value with the object as this
val label = user.run { "$name <${email ?: "no email"}>" }

// with: same as run, but the object is an argument
val summary = with(user) { "$name has ${if (email == null) "no" else "an"} email" }

How to choose

  • Need the object back? apply (configure it) or also (do something with it).
  • Need a different value back? let (with it) or run / with (with this).
  • Nullable receiver? Use the extension forms with ?.: x?.let, x?.run, x?.apply. with(x) has no safe-call form.
  • Prefer it (let, also) when the block also uses the outer this, to avoid confusing the two receivers.

Sources