Scope Functions (let / run / with / also / apply)
Functions that execute a block of code on an object, providing a temporary scope for operations or configurations.
obj.let { it.property }
obj.run { this.method() }
with(obj) { ... }
obj.also { it.doSomething() }
obj.apply { this.property = value }This static page keeps the syntax and examples indexed for search, while the coding app handles interactive exploration and saved references.
What it does
Overview
Functions that execute a block of code on an object, providing a temporary scope for operations or configurations.
Kotlin's scope functions (`let`, `run`, `with`, `also`, `apply`) are higher-order functions that provide a concise way to execute a block of code within the context of an object. They differ primarily in how they refer to the receiver object (either `this` or `it`) and what they return. - `let`: The receiver is available as `it`. It returns the lambda result. Often used for null-safety (`obj?.let { ... }`) or for transforming an object. - `run`: The receiver is available as `this`. It returns the lambda result. Useful for configuring an object and computing a result, or when you need to execute a block of statements on an object where `this` refers to the object itself. - `with`: Not an extension function; it takes the object as an argument. The receiver is available as `this`. It returns the lambda result. Good for performing multiple operations on an object without repeating its name. - `apply`: The receiver is available as `this`. It returns the receiver object itself. Primarily used for object configuration (initializing properties) and fluent API design. - `also`: The receiver is available as `it`. It returns the receiver object itself. Best for performing side-effects (e.g., logging, printing) on an object without altering its value. Choosing the right scope function improves code readability and expressiveness by clearly indicating the intent of the code block. They help avoid temporary variables and enable more fluent, chainable API calls.
Quick reference
Syntax
obj.let { it.property }
obj.run { this.method() }
with(obj) { ... }
obj.also { it.doSomething() }
obj.apply { this.property = value }
See it in practice
Examples
Using 'let' for null-safety and transformation
val name: String? = "Alice"
val length = name?.let {
println("Processing non-null name: $it")
it.length
} ?: 0
println("Name length: $length")
val nullName: String? = null
val nullLength = nullName?.let { it.length } ?: 0
println("Null name length: $nullLength")Processing non-null name: Alice Name length: 5 Null name length: 0
`let` is used with the safe call operator (`?.`) to execute the block only if `name` is not null. It returns the result of the lambda.
Using 'apply' for object configuration
class Person { var name: String = ""; var age: Int = 0 }
val person = Person().apply {
name = "Bob"
age = 30
}
println("Configured Person: ${person.name}, ${person.age}")Configured Person: Bob, 30
`apply` is used to configure properties of `person`. Inside the lambda, `this` refers to the `person` object. It returns the `person` object itself.
Using 'also' for side-effects and 'run' for combined operations
val numbers = mutableListOf(1, 2, 3)
val processedList = numbers.also {
println("Original list before processing: $it")
}.run {
add(4)
map { it * 2 }
}
println("Final processed list: $processedList")
println("Original list after processing: $numbers")Original list before processing: [1, 2, 3] Final processed list: [2, 4, 6, 8] Original list after processing: [1, 2, 3, 4]
`also` logs the original list (side-effect) and returns the list. `run` then adds an element and maps the list, returning the mapped list. Note how `also` returns the original receiver, while `run` returns the lambda's result.
Debug faster
Common Errors
Incorrect return value / unexpected object state
Cause: Confusing the return values of different scope functions (e.g., expecting `apply` to return the lambda result, or `let` to return the receiver). Also, misunderstanding `it` vs `this`.
Fix: Remember: `let` and `run` return the lambda result. `apply` and `also` return the receiver object. `with` returns the lambda result. Use `it` for `let`/`also` and `this` for `run`/`apply`/`with`. Choose the scope function based on its return value and how it refers to the receiver.
val myString = "hello"
val result = myString.apply { toUpperCase() } // 'result' is "hello", not "HELLO"
println(result) // Output: helloRuntime support
Compatibility
Source: Kotlin Documentation
Common questions
Frequently Asked Questions
Functions that execute a block of code on an object, providing a temporary scope for operations or configurations.
Incorrect return value / unexpected object state: Remember: `let` and `run` return the lambda result. `apply` and `also` return the receiver object. `with` returns the lambda result. Use `it` for `let`/`also` and `this` for `run`/`apply`/`with`. Choose the scope function based on its return value and how it refers to the receiver.