Scope Functions Quiz

KOTLIN › Language Idioms

Which scope function returns the context object and exposes it as this?

Answer: apply returns the receiver and exposes it as this.

apply returns the receiver itself and references it as this, making it ideal for configuration that returns the configured object.

You want to log a value as a side effect inside a call chain without changing what is passed along. Which is idiomatic?

Answer: also, which runs on it and returns the same object

also returns the same object and exposes it as it, so it performs a side effect (logging) while the chain continues with the unchanged object.

What does this expression return: val n = str?.let { it.length }, where str is String??

Answer: An Int?: the lambda result, or null if str is null

let returns the lambda result; with ?. the lambda runs only when str is non-null, so n is the length or null otherwise.

Which pair both return the lambda result?

Answer: run and with

run and with both return the lambda result. apply and also are the two that return the context object instead.

Inside an apply block on a Person, how do you set its age property?

Answer: age = 32

apply exposes the object as this, so members can be accessed bare; age = 32 is equivalent to this.age = 32.

Which scope function is a non-extension that takes the object as an argument and exposes it as this?

Answer: with

with is called as with(obj) { }, takes the object as an argument, uses this as the reference, and returns the lambda result.

Why might you prefer also over apply even when both return the object?

Answer: also exposes the object as it, avoiding shadowing outer this

Both return the object, but also uses it (a named/explicit reference) which reads better for side effects that pass the object as an argument and avoids shadowing an outer this.

What distinguishes the non-extension run { } from the extension form obj.run { }?

Answer: It has no receiver object and returns the block's last expression

Non-extension run takes no object; it runs a block of statements and returns the last expression, which is handy for scoping temporary variables where an expression is required.

You have val config: Config? and want to call several of its methods only when it is non-null, then use the block's computed result. Which is most idiomatic?

Answer: config?.run { ... }

config?.run { } executes only when config is non-null, exposes it as this so methods are called bare, and returns the lambda result; with has no safe-call form and apply would return the object instead of a result.

Apart from null-checks, what is an idiomatic use of let?

Answer: Mapping the receiver to a new result while keeping it in a small scope

let returns the lambda result, so it suits mapping a value into a different type, and it limits the introduced variable (it) to the block's scope.

What does user.takeIf { it.isActive } evaluate to when isActive is false?

Answer: null

takeIf returns the receiver when the predicate is true and null otherwise, so a false predicate yields null (takeUnless is its inverse).

Kotlin's standard scope functions (let, run, with, apply, also) are declared inline. What does that imply?

Answer: Lambda bodies inline at the call site, enabling non-local returns

Being inline, the compiler copies the lambda body into the call site, avoiding a runtime lambda allocation and permitting non-local returns from the enclosing function.

What is the value of x in: val x = 5.also { println(it + 1) }?

Answer: 5

also ignores the lambda's result and returns the context object itself, so x is 5 even though the lambda prints 6.

Inside a nested let, you need to reference the outer block's object as well as the inner one. What is the idiomatic fix?

Answer: Name lambda params, e.g. x.let { o -> y.let { i -> ... } }

let exposes the object as the implicit it, which the inner block shadows; naming the lambda parameters makes both objects accessible, and this@let is invalid because let uses it rather than a labeled receiver.

Back to Scope Functions