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. This is lesson 3 of 4. Any 3 lessons of this learning path are free to read in full — after that, CoddyKit PRO unlocks every lesson, plus hands-on practice with a built-in code editor and a 24/7 AI tutor. It is part of the Kotlin Academy learning path, and your progress syncs across the web and the CoddyKit app. The Kotlin Academy course includes 4 lessons in total.
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.
Learn Kotlin with an AI tutor — free
Write and run real code in your browser, get instant help from a 24/7 AI tutor, and pick up where you left off on the web or in the app.
- Courses
- 51
- Lessons
- 203
Frequently Asked Questions
Is the “also: Side Effects Without Changing the Receiver” lesson free?
Yes — any 3 lessons of the Kotlin Academy learning path, including “also: Side Effects Without Changing the Receiver”, are free to read in full here on the web. After that, CoddyKit PRO unlocks every lesson, plus interactive practice with a built-in code editor and a 24/7 AI tutor. The Kotlin Academy course includes 4 lessons in total.
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, so you can start here or from the beginning and move at your own pace. This is lesson 3 of 4.
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