Kotlin Scope Functions
write cleaner and more idiomatic code
✨ Introduction
Kotlin’s scope functions (let, run, with, apply, also) are powerful tools for writing concise, readable code. They allow you to perform operations on objects within a temporary scope, reducing boilerplate and improving clarity. Let’s break down each function with practical examples.
1.
let: Transform and Null-Check
Use let for null-safe transformations or actions on nullable objects:
val name: String? = "Kotlin"
name?.let {
println(it.uppercase()) // "KOTLIN"
it.length // Returns length (last expression)
}🤔 When to use:
- Null-checking nullable variables.
- Transforming an object and returning a result.
2.
run: Configure or Compute
run works on an object (receiver) and returns the last expression:
val result = "Hello".run {
println("Length: $length") // Length: 5
substring(0, 3) // Returns "Hel"
}Non-extension variant:
run {
val x = 5
x * x // Returns 25
}🤔 When to use:
- Initializing objects + computing a value.
- Grouping logic on an object.
3.
with: Group Operations
with is similar to run but takes the receiver as an argument:
val list = mutableListOf(1, 2, 3)
val firstEven = with(list) {
add(4)
firstOrNull { it % 2 == 0 } // Returns 2
}🤔 When to use:
- Performing multiple operations on the same object.
- Avoiding repeated
list.orobject.prefixes.
4.
apply: Initialize Objects
apply returns the receiver after configuration:
val task = Task().apply {
id = 101
priority = HIGH
assignee = "Alice"
}
// Returns configured Task object🤔 When to use:
- Configuring properties during object creation.
- Builder-style initialization.
5.
also: Side Effects
also returns the receiver after performing side effects:
val numbers = listOf(1, 2, 3)
.also { println("Original: $it") } // Logging
.map { it * 2 }🤔 When to use:
- Debugging/logging.
- Performing actions without altering the object.
Key Differences Cheat Sheet
Best Practices
- Avoid nesting scope functions (e.g.,
applyinsidelet). - Use
itforlet/alsoandthisforrun/apply/withto clarify context. - Prefer
takeIf/takeUnlesswithletfor conditional checks:
user.takeIf { it.isActive }?.let { sendEmail(it) }Conclusion
Kotlin’s scope functions eliminate redundancy and make code expressive. Remember:
- Use
letfor null-safe ops. - Use
run/withfor computations. - Use
applyfor initializers. - Use
alsofor side effects.
Master these to write idiomatic Kotlin!
Get Tejas Kanazriya’s stories in your inbox
Join Medium for free to get updates from this writer.
References:
Let me know if you’d like a deep-dive into any specific scope function! 🚀










