also
| Since: | Kotlin 1.0(2016) |
|---|
The Kotlin scope function also is used to insert side effects — such as logging, debugging, or additional processing — on an object. Inside the block, the object is referenced as it, and the return value is the receiver itself.
Syntax
val result = object.also {
// it = the object
println(it) // side effect (e.g., logging)
}
// result is the object itself
Syntax Overview
| Scope Function | Context Reference | Return Value | Use Case |
|---|---|---|---|
| also { } | it | Receiver itself | Used to insert side effects such as logging or debugging. |
| apply { } | this (can be omitted) | Receiver itself | Used for object configuration and initialization. |
| let { } | it | Lambda result | Used for null checks and transformation chains. |
| run { } | this (can be omitted) | Lambda result | Combines object setup with computation. |
Sample Code
sample_scope_also.kt
fun main() {
// Use also to insert a log in the middle of a method chain.
val numbers = mutableListOf(1, 2, 3)
.also { println("Before transform: $it") } // Before transform: [1, 2, 3]
.map { it * 2 }
.also { println("After transform: $it") } // After transform: [2, 4, 6]
println(numbers) // [2, 4, 6]
val text = "Hello, Kotlin!"
.also { println("Length: ${it.length}") } // Length: 14
.uppercase()
println(text) // HELLO, KOTLIN!
// also can also be used to insert validation.
data class User(val name: String, val age: Int)
fun createUser(name: String, age: Int): User {
return User(name, age).also {
require(it.age >= 0) { "Age must be 0 or greater" }
println("User created: $it")
}
}
val user = createUser("user_x", 28)
println(user)
// User created: User(name=user_x, age=28)
// User(name=user_x, age=28)
}
scope_also.kt
kotlinc scope_also.kt -include-runtime -d scope_also.jar java -jar scope_also.jar Before transform: [1, 2, 3] After transform: [2, 4, 6] [2, 4, 6] Length: 14 HELLO, KOTLIN! User created: User(name=user_x, age=28) User(name=user_x, age=28)
Common Mistakes
NG example 1: Expecting also to return a transformed value — also always returns the receiver, so any result from operations inside the block is discarded
NG example 2: Using this inside also — also uses it, not this
NG example 3: Using also to configure object properties — it works, but apply makes the intent much clearer
fun main() {
val numbers = listOf(1, 2, 3)
val doubled = numbers.also { it.map { n -> n * 2 } }
println(doubled) // [1, 2, 3] (not transformed)
}
Use map or let when transformation is the goal
sample_scope_also_mistakes.kt
fun main() {
val numbers = listOf(1, 2, 3)
val doubledCorrect = numbers.map { it * 2 }
println(doubledCorrect) // [2, 4, 6]
// Inside also, reference the object via it
val text = "Hello, Kotlin"
text.also { println(it.length) } // 13
// Use apply for object configuration — the intent is clearer
data class Config(var host: String = "", var port: Int = 0)
val config = Config().apply {
host = "localhost"
port = 8080
}
println(config) // Config(host=localhost, port=8080)
}
The command looks like this:
kotlinc sample_scope_also_mistakes.kt -include-runtime -d sample_scope_also_mistakes.jar java -jar sample_scope_also_mistakes.jar [2, 4, 6] 13 Config(host=localhost, port=8080)
Overview
The key feature of also is that it lets you add side effects without changing the flow of your code. It is particularly useful for inserting debug logs or adding validation in the middle of a method chain.
Both also and apply return the receiver itself, but they differ in how they reference the context: also uses it, while apply uses this. Use also when operating on the object from the outside, and apply when configuring the object itself.
See apply for object initialization, and let for null checks.
If you find any errors or copyright issues, please contact us.