How to Choose Scope Function in Kotlin: Guide with Examples
Choose a Kotlin
scope function based on your goal: use let to work with a nullable object and return a result, apply to configure an object and return it, run to execute a block and return its result, with to call multiple methods on an object without extension, and also to perform additional actions without changing the object. The choice depends on whether you need the object as this or it, and what you want to return.Syntax
Kotlin has five main scope functions: let, run, with, apply, and also. Each has a similar syntax but differs in how the object is referenced and what is returned.
- let: object is
it, returns lambda result - run: object is
this, returns lambda result - with: takes object as argument,
thisinside, returns lambda result - apply: object is
this, returns the object - also: object is
it, returns the object
kotlin
val resultLet = "Hello".let { println(it) it.length } val resultRun = "Hello".run { println(this) length } val resultWith = with("Hello") { println(this) length } val resultApply = StringBuilder().apply { append("Hello") append(" World") } val resultAlso = "Hello".also { println(it) }
Output
Hello
Hello
Hello
Hello
Example
This example shows how to choose scope functions based on what you want to do: configure an object, run code with a result, or perform side effects.
kotlin
data class Person(var name: String, var age: Int) fun main() { // Use apply to configure and return the object val person = Person("", 0).apply { name = "Alice" age = 25 } println("Person after apply: $person") // Use let to work with nullable and return a result val nullableName: String? = person.name val length = nullableName?.let { println("Name is $it") it.length } ?: 0 println("Name length: $length") // Use run to execute block with this and return result val greeting = person.run { "Hello, my name is $name and I am $age years old." } println(greeting) // Use also to perform side effects and return the object val updatedPerson = person.also { println("Updating age") it.age = 26 } println("Person after also: $updatedPerson") // Use with to call multiple methods on an object val infoLength = with(person) { println("Person info: $name, $age") name.length + age } println("Info length: $infoLength") }
Output
Person after apply: Person(name=Alice, age=25)
Name is Alice
Name length: 5
Hello, my name is Alice and I am 25 years old.
Updating age
Person after also: Person(name=Alice, age=26)
Person info: Alice, 26
Info length: 31
Common Pitfalls
Common mistakes include confusing this and it references, expecting the wrong return value, or using a scope function that doesn't fit the task.
- Using
applywhen you need a result from the lambda (it returns the object, not the lambda result). - Using
letwhen you want to configure an object (it returns the lambda result, not the object). - Forgetting
withis not an extension function but a regular function taking the object as argument.
kotlin
val list = mutableListOf<Int>() // Wrong: apply returns the object, not the lambda result val sizeWrong = list.apply { add(1) add(2) size // this is ignored } println(sizeWrong) // prints the list, not size // Right: run returns the lambda result val sizeRight = list.run { add(3) add(4) size } println(sizeRight) // prints 4
Output
[1, 2, 3, 4]
4
Quick Reference
| Scope Function | Object Reference | Return Value | Use Case |
|---|---|---|---|
| let | it | Lambda result | Nullable object handling, chaining calls |
| run | this | Lambda result | Execute block with object as receiver, return result |
| with | this | Lambda result | Call multiple methods on object, not extension |
| apply | this | Object | Configure object, return it for chaining |
| also | it | Object | Perform side effects, return object |
Key Takeaways
Pick scope functions based on whether you need the object as 'this' or 'it' inside the block.
Use 'apply' and 'also' when you want to return the original object after configuration or side effects.
Use 'let', 'run', or 'with' when you want to return the result of the lambda block.
Remember 'with' is not an extension function but takes the object as an argument.
Avoid mixing up return values to prevent bugs and unexpected behavior.