Account for copying and allocation
A convenient expression can hide repeated work. Appending with result = result + item creates new collection values repeatedly; building locally in a mutable buffer can avoid copying an ever-growing prefix.
fun labels(count: Int): List<String> {
require(count >= 0)
return buildList {
repeat(count) { index -> add("Lesson ${index + 1}") }
}
}
The builder confines mutation to construction and returns a read-only result. This is different from exposing a shared MutableList to callers. A read-only API is useful, but its elements can still be mutable objects.
Big-O reasoning predicts growth, not exact timings. Benchmark realistic input sizes before choosing sequences, specialized arrays, or custom loops. Avoid measurements dominated by printing, startup, or one-time compilation.
Exercise
Compare repeated + with a single builder for increasing input sizes. First confirm identical output; then measure warmed-up runs using a suitable benchmark harness.
Check: explain why reducing allocation may matter even when elapsed time looks similar in a tiny example.