Phase 2 · Functions & FunctionalModule 10~32 min read

Scope Functions

let, run, with, apply, and also — the small functions that make Kotlin so expressive.

What you'll learn

Kotlin has five little functions — let, run, with, apply, and also — that run a block of code in the context of an object. They're a huge part of what makes Kotlin so concise and expressive. This module demystifies them.

By the end you'll be able to:

  • Use the five scope functions confidently
  • Understand it vs this and result vs receiver
  • Pick the right one for each situation

The five at a glance

They differ in just two ways: how they refer to the object (as it or as this), and what they return (the lambda's result, or the object itself):

FunctionObject isReturnsTypical use
letitlambda resultnull-safe transforms
runthislambda resultconfigure then compute a result
withthislambda resultoperate on an object (not an extension)
applythisthe objectconfigure and return the object
alsoitthe objectside effects like logging

let

let is the most common. It runs a block with the object as it and returns the block's result — perfect with a safe call for "do this only if not null" and for transforming a value into something else:

Let.kt
val name: String? = "Sara"

val length = name?.let {
    println("Processing $it")   // 'it' is the value, non-null here
    it.length                   // the last line is what let returns
}
println(length)   // 4

apply & also

Both return the object (so you can chain), but differ in reference. apply uses this, making it ideal for configuring an object — you call its members directly with no prefix:

Apply.kt
val sb = StringBuilder().apply {
    append("Hello")        // 'this' is the StringBuilder — no prefix needed
    append(", ")
    append("Kotlin!")
}                          // apply returns the StringBuilder itself

println(sb)

also uses it and is meant for side effects that don't change the object — logging, validation, debugging — slotted into a chain:

Also.kt
val numbers = mutableListOf(1, 2, 3)

numbers
    .also { println("Before adding: $it") }  // a side effect; returns the list
    .add(4)

println("After: $numbers")

Choosing one

Two questions decide it: do you want the object back or a computed result, and is it or this nicer to read?

Which scope function?

let

transform / null checks

object is it · returns lambda result

run / with

configure + compute

object is this · returns lambda result

also

side effects (logging)

object is it · returns the object

apply

configure & return it

object is this · returns the object

Tip

Simple heuristics: apply to build/configure an object, also to log or peek without changing it, let for null-safe transforms. Don't overthink it — and don't nest them, which quickly becomes unreadable.

Recap & quick check

Key takeaways

  • Scope functions run a block in the context of an object; they differ by reference (it/this) and return (result/object).
  • let: object is 'it', returns the lambda result — great for null-safe transforms.
  • apply: object is 'this', returns the object — ideal for configuration.
  • also: object is 'it', returns the object — ideal for side effects like logging.
  • run/with: object is 'this', return the lambda result. Pick the one that reads best; avoid nesting them.

Quick check

1. In a 'let' block, how do you refer to the object?

2. Which scope function is best for configuring an object and returning it?

3. What does 'also' return?

4. Which two things distinguish the scope functions?

5. What's a good use of 'let'?

Great — these little functions unlock very idiomatic Kotlin. Next up: Module 11 — Extension Functions & Properties.