also: Side Effects Without Changing the Receiver
Use also for logging, debugging, and side-effect-only operations.
also: Side Effects Without Changing the Receiver is a free Kotlin Academy lesson on CoddyKit — lesson 3 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Kotlin Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
also at a Glance
also runs a block with the receiver as it and returns the receiver unchanged. Perfect for side effects — logging, debugging, validation — without disrupting a chain.
Basic also
also { ... } performs a side effect and yields the same value back, so calls flow naturally.
fun main() {
val nums = listOf(1, 2, 3, 4)
.also { println("input: $it") }
.filter { it % 2 == 0 }
.also { println("filtered: $it") }
println(nums)
}also for Logging
Add log statements mid-pipeline without breaking the flow.
fun main() {
val processed = " Hello, Kotlin! "
.also { println("raw: '$it'") }
.trim()
.also { println("trimmed: '$it'") }
.uppercase()
println(processed)
}also for Debugging
Use also to inspect intermediate state during a refactor — drop it later without changing the chain.
fun main() {
val sum = (1..5).toList()
.also { println("list: $it") }
.sum()
.also { println("sum: $it") }
println("final: $sum")
}also vs apply
apply uses this (better for assignments). also uses it (better for explicit references and side effects).
class Counter {
var value: Int = 0
}
fun main() {
val c = Counter().apply { value = 10 } // uses this implicitly
val d = Counter().also { it.value = 10 } // uses it explicitly
println("${c.value} / ${d.value}")
}also for Initialization Side Effects
Useful when you need to do something with an object during creation that isn't setting a property.
class Repository {
val cache = mutableMapOf<String, String>()
fun init() = println("Repository initialized")
}
fun main() {
val r = Repository().also { it.init() }
r.cache["key"] = "value"
println(r.cache)
}also Returns Original
The receiver passes through unchanged — easy to chain.
fun main() {
val len = "Hello".also { println("got: $it") }.length
println(len) // 5
}also for Validation
Run assertions mid-chain.
fun main() {
val n = listOf(1, 2, 3, 4)
.filter { it > 0 }
.also { require(it.isNotEmpty()) { "must have positives" } }
.sum()
println(n)
}Combining also and let
Use also for side effects and let for transformation in the same pipeline.
fun main() {
val raw: String? = " 42 "
val n = raw
?.also { println("raw: '$it'") }
?.let { it.trim().toIntOrNull() }
?.also { println("parsed: $it") }
println(n)
}also for Adding to a Collection
Add a constructed object to a list inline.
class User(val name: String)
fun main() {
val users = mutableListOf<User>()
val ada = User("Ada").also { users.add(it) }
val ben = User("Ben").also { users.add(it) }
println(users.map { it.name })
}When to Use also
Reach for also when you need a side effect (log, validate, register) but you want the original value to flow through.
fun main() {
val total = listOf(10, 20, 30, 40, 50)
.also { println("count: ${it.size}") }
.filter { it >= 30 }
.also { println("kept: $it") }
.sum()
println("total: $total")
}Anti-Pattern: also for Reassignment
Don't use also when you actually need to transform — that's what let/run are for.
fun main() {
val name = "ada"
// BAD: also returns receiver, so upper is wrong
// val upper = name.also { it.uppercase() } // upper == "ada"
val upper = name.let { it.uppercase() }
println(upper) // ADA
}Quick Check
What value does also return after executing its block?
Recap
also runs a side-effect block with it and returns the receiver. Use it for logging, debugging, validation, registration — anywhere you need a peek without altering the value. For transformations, use let or run instead.
Frequently asked questions
Is the “also: Side Effects Without Changing the Receiver” lesson free?
Yes — the full text of “also: Side Effects Without Changing the Receiver” is free to read here on the web, and the Kotlin Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Kotlin Academy course, upgrade to CoddyKit PRO.
What will I learn in “also: Side Effects Without Changing the Receiver”?
Use also for logging, debugging, and side-effect-only operations. You practise Kotlin Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start Kotlin Academy?
No prior experience is required. Kotlin Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 3 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “also: Side Effects Without Changing the Receiver” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this Kotlin Academy lesson?
Yes. Every Kotlin Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- apply and with: Configure and Return
- let and run: Transform and Scope
- also: Side Effects Without Changing the Receiver
- Choosing the Right Scope Function: Decision Guide