skip to content

What does the apply scope function do, and why is it convenient for configuring an object right after you create it?

level: juniorimportance: must knowfreq 78%

answer

  1. Receiver block T.() -> Unit
  2. Returns this (the receiver)
  3. Configure-in-place, no temp val
  4. this not it (vs also)
  5. inline, works on any type

basics

~10 s

apply runs a block on an object, lets you set its properties using 'this', and returns that same object. So you can create something and configure it in one expression.

solid answer

~40 s

apply is a Kotlin scope function declared as fun <T> T.apply(block: T.() -> Unit): T. Inside the block the object is the receiver (this), so you reference properties and methods directly without a prefix. The block returns Unit, but apply itself returns the receiver object. That makes it ideal for the builder idiom: Request().apply { url = u; header("k", v) } creates a Request, mutates it in place, and yields the configured Request as the value of the expression. It avoids a temporary val plus repeated references, keeps configuration grouped, and works on any type (no special interface needed). Compare with also, where the object is the argument it instead of the receiver.

code

kotlin · 13 lines
kotlin
data class Request(
    var url: String = "",
    var method: String = "GET"
) {
    val headers = mutableMapOf<String, String>()
    fun header(k: String, v: String) { headers[k] = v }
}

val request = Request().apply {
    url = "https://api.example.com"
    method = "POST"
    header("Accept", "application/json")
} // request is the fully configured Request

go deeper

for a junior

Knows apply runs a block with this as the object and returns that object; can write Request().apply { ... }.

for a middle

Contrasts apply with also/let and explains the receiver vs argument distinction and the Unit-vs-receiver return.

for a senior

Notes apply is inline, works on any T, and frames it as the simplest receiver-lambda builder; picks it deliberately over also/let.

for a principal

Discusses when this terse idiom helps or hurts readability/API design and when a real type-safe builder is warranted instead.

## What apply is `apply` is one of Kotlin's standard *scope functions* (alongside `let`, `run`, `with`, `also`). Its signature in the standard library is: ```kotlin public inline fun <T> T.apply(block: T.() -> Unit): T { block() return this } ``` Two things define its behavior: - **Receiver block (`T.() -> Unit`)** — the lambda has the object as its *receiver*. Inside the block, `this` is the object, so you can write `url = u` or `header("k", v)` directly, with no `it.`/`obj.` prefix. - **Returns the receiver (`: T`)** — the block's own result (`Unit`) is discarded; `apply` returns the same object it was called on. This is what makes it chainable and usable as an expression. ## The builder idiom Because `apply` returns the configured object, you can construct-and-configure in a single expression: ```kotlin val request = Request().apply { url = "https://api.example.com" // this.url method = "POST" header("Accept", "application/json") // this.header(...) } ``` This is the simplest *receiver-lambda builder*: no dedicated builder class, no interface, no `build()` call. Any mutable object works because `apply` is an extension on `T` (the generic type), available on everything. ## Why it's convenient - **No temporary variable** — you don't need `val r = Request(); r.url = ...; r.method = ...` and then return `r`. - **Grouped configuration** — all the setup lives in one visually scoped block. - **Direct member access** — receiver scope means terse `name = ...` instead of `r.name = ...`. - **Inlined** — `apply` is an `inline` function, so there is no lambda-allocation or call overhead at runtime. ## apply vs also `also` has signature `fun <T> T.also(block: (T) -> Unit): T`. It also returns the receiver, but the object is passed as the *argument* `it`, not as `this`. Use `apply` to **configure** (`this.x = ...`); use `also` for **side effects** that read the object (`also { log(it) }`).

  • What does the apply block itself return, and does that matter?
    The block returns Unit, which is discarded. apply always returns the receiver, so the last expression in the block is irrelevant to apply's result.
  • When would you choose also instead of apply?
    When the lambda is a side effect that reads the object (logging, validation, registering it) rather than configuring it — also exposes the object as it, keeping the call's intent (peek/side-effect) clear.

Like buying flat-pack furniture and assembling it before handing the finished piece to someone — you get the same item back, just set up.

saying these in an interview costs you the question

  • Saying apply returns the result of the last line in the block
  • Confusing apply (this) with also (it)
  • Thinking the object must implement a special builder interface
  • Claiming apply mutates a copy rather than the original object
  • Saying apply only works on data classes

context