let, run, also, apply, with
In this page:
let for Null Checks and Transformations
let executes a block with the receiver available as it and returns whatever the block produces, and is commonly combined with ?. to run code only when a nullable value is present.
Example: let for Null Checks and Transformations
fun main() {
val name: String? = "Kotlin"
val length = name?.let {
println("Name is not null: $it")
it.length
}
println("Length: $length")
}
Login to try C/C++/Java/PHP code in the editor
run for Grouped Computation
run executes a block with the receiver available as this, returning the block's result -- useful for computing a value from several steps involving that receiver's members directly.
Example: run for Grouped Computation
class Config(var name: String = "", var port: Int = 8080)
fun main() {
val summary = Config().run {
name = "Server"
port = 9090
"$name running on port $port"
}
println(summary)
}
Login to try C/C++/Java/PHP code in the editor
also for Side Effects
also runs a block with the receiver as it but always returns the original receiver unchanged, which makes it ideal for logging or debugging in the middle of a chain of calls.
Example: also for Side Effects
fun main() {
val numbers = mutableListOf(1, 2, 3)
.also { println("Original list: $it") }
numbers.add(4)
println("After adding: $numbers")
}
Login to try C/C++/Java/PHP code in the editor
apply for Configuring an Object
apply runs a block with the receiver as this and returns that same receiver, making it perfect for setting up several properties on a newly created object in one expression.
Example: apply for Configuring an Object
class Person {
var name: String = ""
var age: Int = 0
}
fun main() {
val person = Person().apply {
name = "Ana"
age = 30
}
println("${person.name}, ${person.age}")
}
Login to try C/C++/Java/PHP code in the editor
with for Operating on an Existing Object
with(receiver) { ... } is not an extension function but a regular function that takes an object and a lambda where that object is available as this, returning the lambda's result -- useful when you already have the object in hand.
Example: with for Operating on an Existing Object
class Rectangle(val width: Int, val height: Int)
fun main() {
val rect = Rectangle(4, 5)
val area = with(rect) {
width * height
}
println("Area: $area")
}
Login to try C/C++/Java/PHP code in the editor
- Mixing up
applyandalso;applyreturns the receiver itself (this) whilealsoalso returns the receiver but exposes it asit. - Mixing up
letandrun; both usethis/itdifferently and return the lambda's result, easy to misremember which uses which. - Overusing scope functions to chain many unrelated operations together, making the code harder to read than plain statements would be.
letruns a block with the value asitand returns the block's result -- often used with?.for null checks.runruns a block with the value asthisand returns the block's result.alsoruns a block with the value asitbut returns the original value -- good for side effects like logging.applyruns a block with the value asthisand returns the original value -- good for configuring an object.
Chapter Quiz — Complete all 6 topics to unlock
0/6 topics done
Complete these topics first: