skip to content

apply & also

apply and also both return the original object, differing only in this versus it. apply is the builder-style configuration block, also is where you slot logging or a side effect into a chain without breaking it.

part ofKotlinoverview, primer and where to startread it →
on this pageshow

questions

5

What do Kotlin's apply { } and also { } return, and how does each give you access to the object inside the lambda?

level: juniorimportance: must knowfreq 80%

answer

  1. Both return the receiver, not the lambda result
  2. apply = this, also = it
  3. apply configures, also side-effects/logs
  4. let/run return last expression instead
  5. All are inline functions

basics

~10 s

Both apply and also return the same object you called them on. Inside apply you use it as this; inside also you use it as it. Neither changes what value comes out.

solid answer

~40 s

Both apply and also are extension functions that return the receiver object itself (the thing before the dot), not the result of the lambda. The difference is how the lambda accesses that object: apply passes it as the lambda receiver (this), so you can call members directly without a name; also passes it as the single argument it. Because they return the original object, you can keep chaining method calls afterward. Use apply for configuring an object (set properties, call setters) and also for side effects like logging, validation, or adding to a list, where the it name keeps the original object readable. Compare with let/run, which return the lambda's last expression instead.

code

kotlin · 7 lines
kotlin
val person = Person().apply {
    name = "Lena"   // this.name
    age = 30
}.also {
    println("created: ${it.name}") // it == person
}
// person is fully configured, logged, and === to the apply/also result

go deeper

for a junior

Knows both return the object and that apply=this, also=it.

for a middle

Explains why returning the receiver enables chaining and contrasts with let/run.

for a senior

Mentions the inline/lambda-with-receiver signatures and picks the idiomatic function per use case.

for a principal

Frames apply/also within the whole scope-function matrix (this/it x receiver-vs-lambda-result) and team readability conventions.

## The core fact `apply` and `also` are two of Kotlin's five **scope functions** (the others are `let`, `run`, and `with`). A *scope function* lets you run a block of code on an object inside a temporary scope. The thing you call the function on is the **receiver** — the object before the dot. The defining trait of `apply` and `also`: **they both return the receiver object itself**, not whatever the lambda evaluates to. This is what makes them ideal for fluent chains. ## How the object is exposed inside the lambda - **`apply`** uses a *lambda with receiver*. Inside the braces, the object is bound to **`this`**, so you can reference its members directly (often omitting `this`). Its signature is roughly `inline fun <T> T.apply(block: T.() -> Unit): T`. - **`also`** passes the object as a *regular argument* named **`it`**. Its signature is `inline fun <T> T.also(block: (T) -> Unit): T`. ```kotlin val list = mutableListOf(1, 2, 3) // apply: object is `this` val a = list.apply { add(4) // == this.add(4) add(5) } // returns the SAME list // also: object is `it` val b = list.also { println("size is ${it.size}") } // returns the SAME list println(a === b) // true — both are the original list ``` ## Why "returns the receiver" matters Because the original object comes back out, you can configure or peek at an object **in the middle of an expression** without breaking the chain: ```kotlin val user = User() .apply { name = "Ada" } // configure, get User back .also { log.info("built $it") } // log, get User back ``` Contrast: `let` and `run` return the **last expression** of the lambda, so they *transform* a value. `apply`/`also` never transform — they hand the object straight back. ## Quick mental model - `apply` → "configure this object" (`this`, returns object). - `also` → "do something on the side with `it`" (`it`, returns object). All four (`let`, `run`, `apply`, `also`) plus `with` are declared `inline`, so there is no lambda-allocation or call overhead at runtime.

  • If you wrote `val x = list.apply { add(1) }`, what is x?
    x is the same list object (with 1 appended) — apply returns the receiver, not the result of add.
  • Could you swap apply for also and keep `this.name = ...`?
    No. also exposes the object as it, not this, so you'd have to write it.name = ... instead.

apply is like handing a builder the object and saying 'set it up'; also is like passing it to an observer who notes something and hands it right back.

saying these in an interview costs you the question

  • Saying apply returns the lambda's last expression (that's let/run)
  • Claiming also uses this instead of it
  • Thinking apply/also create a copy rather than returning the same instance
  • Confusing apply with also's receiver style

context

open as a page

Show how apply is used for builder-style object configuration, and explain why it reads better than assigning the object to a variable first.

level: middleimportance: must knowfreq 70%

basics

~20 s

apply lets you create an object and set its properties in one block, using this so you skip repeating the variable name. It returns the finished object, so the whole thing is a single expression.

open as a page

How is also used for side-effecting and logging inside a call chain, and why is it a better fit than apply for that job?

level: middleimportance: should knowfreq 60%

basics

~20 s

also lets you slip a side effect — like logging, validating, or saving — into a chain without breaking it. It hands the object back unchanged, and you read it as it, which keeps logs and effects clear.

open as a page

Given a chain mixing apply and also with a non-Unit last line in the block, what value flows out? Trace it and explain.

level: seniorimportance: should knowfreq 45%

basics

~10 s

No matter what the last line of an apply or also block evaluates to, the chain keeps flowing the original object forward. The block's result is discarded; only the receiver comes out.

open as a page

You see new code using also { } to initialize fields and apply { } to register the object in a global registry. Critique these choices and propose the idiomatic split.

level: seniorimportance: nice to knowfreq 30%

basics

~10 s

The two are swapped. apply (this) is for configuring the object's own fields; also (it) is for side effects like registering it somewhere. Flip them so the code reads as intended.

open as a page