Lambdas Workbook (Part 5): inline and Receivers


Practice problems for Why Lambdas Are Free, and Lambdas That Read Like Syntax. Each takes a minute or two. Write your own answer first, then click Show answer — nothing here is a trick question, just direct practice of the syntax from the lesson.

inline

1. Mark it inline

Make this higher-order function’s lambda cost nothing at runtime:

fun runTwice(block: () -> Unit) { block(); block() }
Show answer Hide answer
inline fun runTwice(block: () -> Unit) { block(); block() }

2. What inlining produces

Given inline fun repeatTimes(n: Int, action: (Int) -> Unit) { for (i in 0 until n) action(i) }, write the code that repeatTimes(2) { println(it) } effectively becomes after inlining.

Show answer Hide answer
for (i in 0 until 2) println(i)

No lambda object, no extra call — the body is copied in.

3. reified

Write inline fun <reified T> Any.asOrNull(): T? returning the receiver as a T, or null on a mismatch.

Show answer Hide answer
inline fun <reified T> Any.asOrNull(): T? = this as? T

reified keeps T at runtime; it works only because the function is inline.

4. noinline

In inline fun run2(a: () -> Unit, b: () -> Unit), mark b so it is not inlined (so you can store it in a variable).

Show answer Hide answer
inline fun run2(a: () -> Unit, noinline b: () -> Unit) {
    a()
    val saved = b
    saved()
}

lambdas with a receiver

5. A receiver lambda type

Declare val build of type StringBuilder.() -> Unit whose body appends "hi".

Show answer Hide answer
val build: StringBuilder.() -> Unit = { append("hi") }

The StringBuilder. prefix makes this inside the lambda a StringBuilder, so append needs no qualifier.

6. Configure with apply

Use apply to create a StringBuilder, append "a" then "b", and keep the builder.

Show answer Hide answer
val sb = StringBuilder().apply {
    append("a")
    append("b")
}

7. buildString

Use buildString to assemble "Hello, world".

Show answer Hide answer
val text = buildString {
    append("Hello, ")
    append("world")
}

8. apply returns the object

Configure a File("out.txt") by calling createNewFile() via apply, assigning the resulting File to f.

Show answer Hide answer
val f = File("out.txt").apply { createNewFile() }

apply returns the receiver, so the whole expression is the configured File.

your own receiver builder

9. A receiver-lambda function

Write buildInts(block: MutableList<Int>.() -> Unit): List<Int> that creates a list, applies the block to it, and returns it.

Show answer Hide answer
fun buildInts(block: MutableList<Int>.() -> Unit): List<Int> {
    val list = mutableListOf<Int>()
    list.block()
    return list
}

10. Use your builder

Using buildInts, build the list [1, 2, 3] — calling add without any prefix.

Show answer Hide answer
buildInts {
    add(1)
    add(2)
    add(3)
}

Inside the block the receiver is the MutableList, so add resolves to this.add.

11. Why the bare calls work

In buildInts { add(10) }, what is add actually being called on, and why don’t you write it explicitly?

Show answer Hide answer
buildInts {
    this.add(10)   // 'this' is the MutableList — the receiver
    add(10)        // identical: the receiver is implicit
}

A receiver lambda makes the receiver this, and this. is optional — exactly like inside a member function.


Back to the lesson, Why Lambdas Are Free. That completes the lambda series — next in the curriculum: classes.

Comments