Show how takeIf chained with the Elvis operator expresses a conditional value, and explain why this is preferred over an if/else here.
answer
- Pattern: x.takeIf { p } ?: fallback
- Elvis substitutes when left is null
- RHS can be error/throw/return
- Avoids repeating the receiver
- Don't over-stack — prefer when/if for long logic
basics
~10 sUse value.takeIf { condition } ?: fallback. If the condition holds you get the value, otherwise the fallback. It reads as one fluent expression instead of a multi-line if/else.
solid answer
~40 sThe idiom is `receiver.takeIf { predicate } ?: fallback`. `takeIf` produces `T?` — the receiver or `null` — and the Elvis operator `?:` substitutes the `fallback` whenever the left side is `null`. This keeps everything as a single expression you can chain further (`.let`, `.also`, etc.) and assign directly to a `val`. Compared with `if (predicate) receiver else fallback`, the `takeIf`/`?:` form avoids repeating the receiver, works neatly inside larger call chains, and lets the right-hand side of `?:` be an expression that throws (`?: error(...)`) or returns early (`?: return`). The cost: it allocates nothing thanks to `inline`, but readability degrades if the predicate is long or if you stack multiple `takeIf`s — at that point a plain `if`/`when` is clearer.
code
kotlin · 5 linesfun resolveTimeout(raw: Int?): Int =
raw?.takeIf { it > 0 } ?: DEFAULT_TIMEOUT
fun requireToken(header: String): String =
header.takeUnless { it.isBlank() } ?: error("Authorization header required")go deeper
Can write the x.takeIf { } ?: fallback pattern and read it correctly.
Explains that takeIf yields T? and Elvis supplies the default, and knows ?: short-circuits and can throw/return.
Articulates the composability and no-repetition benefits and the readability limits of stacking takeIf.
Sets guidance on when expression-style nullable chaining improves a codebase versus when explicit if/when is mandated for clarity and reviewability.
## The idiom The canonical pattern is: ```kotlin val result = receiver.takeIf { predicate } ?: fallback ``` ## How it works step by step 1. `takeIf { predicate }` returns the receiver if `predicate` is true, else `null`. Its static type is `T?`. 2. The **Elvis operator `?:`** evaluates its left operand; if it is non-null it yields that value, otherwise it yields the right operand (`fallback`). The right operand is only evaluated when needed (short-circuit). 3. The whole thing is **one expression**, so it can be assigned, returned, or chained. ```kotlin val port: Int = rawPort.takeIf { it in 1..65535 } ?: 8080 val user = repo.findById(id).takeIf { it.isActive } ?: throw NotFoundException(id) val trimmed = input.trim().takeIf { it.isNotEmpty() } ?: return null ``` ## Why prefer it over if/else here - **No repetition of the receiver.** `if (input.isNotEmpty()) input else "-"` mentions `input` twice; `input.takeIf { it.isNotEmpty() } ?: "-"` mentions it once. - **Composability.** Because the result is still an expression, you can keep chaining: `text.takeIf { it.isNotBlank() }?.uppercase() ?: "NONE"`. - **Powerful right-hand sides.** `?: error(...)`, `?: return`, `?: throw`, or a computed default all work because Elvis takes any expression (including `Nothing`-typed ones). ## When NOT to use it - The predicate is long or has side effects — a `when`/`if` block reads better. - You stack several `takeIf`/`takeUnless` calls; nested nullability becomes confusing. - The two branches produce genuinely different shapes — `if`/`when` makes the branching explicit. ## Gotcha: null receivers `takeIf` is itself callable on a nullable receiver via `?.`: `maybeNull?.takeIf { ... }`. Without the `?.`, calling `takeIf` on a `T?` would pass a possibly-null `it` into the predicate.
- Rewrite if (s.isNotBlank()) s else "-" using takeIf.s.takeIf { it.isNotBlank() } ?: "-"
- Can the Elvis right-hand side throw?Yes — it can be any expression, including one of type Nothing such as throw, error(...), or return.
saying these in an interview costs you the question
- Claiming takeIf alone provides the fallback (it returns null, not the default)
- Forgetting that the result before ?: is nullable
- Stacking many takeIf calls where if/when would be clearer
- Saying Elvis evaluates both sides eagerly (it short-circuits)