Show how apply is used for builder-style object configuration, and explain why it reads better than assigning the object to a variable first.
answer
- apply = build/configure in one expression
- this is implicit, no repeated variable
- Great for Java-style mutable objects
- Returns the configured object for a val
- Nested apply -> use this@Label or also
basics
~20 sapply 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.
solid answer
~40 sapply turns object setup into a single configuration expression. You call it on a freshly constructed object; inside the block the object is the receiver (this), so you set properties and call setters by name without repeating a variable. Because apply returns that same object, the whole expression yields the configured instance, which you can assign or pass directly. This is especially valuable for Java-style mutable objects (e.g. an Intent, a StringBuilder, a request DTO, a Paint) that lack a Kotlin constructor with named arguments. It groups all mutation in one scope, avoids a temporary var, and keeps the object immutable from the caller's view (you can assign to a val). The trade-off: apply hides this, so deeply nested applys can get ambiguous about which this you mean.
code
kotlin · 6 linesval paint = Paint().apply {
color = Color.RED
strokeWidth = 4f
isAntiAlias = true
}
// paint is ready and immutably bound as a valgo deeper
Can write a basic apply block that sets a couple of properties.
Explains readability wins (no repeated name, single expression, val binding) and where apply fits the Java-interop builder pattern.
Calls out the nested-this shadowing pitfall and when to finish with run/let for a transformed result.
Sets team conventions: apply only for pure configuration, labeled-this rules, and where a real Builder/DSL beats apply for complex graphs.
## The problem apply solves Many objects — especially ones coming from Java libraries — are built by constructing them empty and then setting fields one by one. Without scope functions you write: ```kotlin val req = HttpRequest() req.method = "POST" req.url = "/login" req.timeout = 5000 // ...now use req ``` This needs a `var`/`val` you repeat on every line and separates construction from use. ## The apply form `apply` is a *lambda with receiver* (`fun <T> T.apply(block: T.() -> Unit): T`). The receiver `this` is the object, and it **returns the same object**, so configuration becomes one expression: ```kotlin val req = HttpRequest().apply { method = "POST" // this.method url = "/login" timeout = 5000 } // req is fully configured here ``` ### Why this reads better - **No repeated name.** You never re-type `req.` — `this` is implicit. - **Single expression.** The result is the configured object, so you can pass it inline: `send(HttpRequest().apply { ... })`. - **Grouped scope.** All mutation lives in one visually distinct block, signaling "this is setup." - **Keeps the binding a `val`.** You don't need a mutable temporary that gets reassigned. ## Classic real-world examples ```kotlin // Android Intent val intent = Intent(this, MainActivity::class.java).apply { putExtra("id", 42) flags = Intent.FLAG_ACTIVITY_NEW_TASK } // StringBuilder val s = StringBuilder().apply { append("Hello, ") append("world") }.toString() ``` ## Caveats - **Nested apply ambiguity.** If you nest `apply` inside `apply`, the inner `this` shadows the outer; use a *labeled this* (`this@Outer`) or switch the outer one to `also` (which uses `it`) to disambiguate. - **Not for transformation.** If the next step needs a *different* value (e.g. `.toString()` of the builder), apply alone isn't enough — you finish with another call, or use `run`/`let`. - **Side effects vs config.** Keep apply for configuration; reach for `also` when the block is a side effect (logging) rather than mutation of the object.
- How would you disambiguate this in a nested apply?Use a labeled this: [email protected], or change the outer scope function to also so the outer object becomes it.
- When does apply NOT fit configuration?When the result must be a transformed value (e.g. builder.toString()) — apply returns the builder, so you add a finishing call or use run/let.
saying these in an interview costs you the question
- Using apply but then ignoring the returned object and reconstructing it
- Putting heavy side effects/logging in apply instead of also
- Nesting applys without realizing this is shadowed
- Reaching for a var temporary when apply removes the need