Closures and variable capture in Kotlin - Time & Space Complexity
Let's explore how the time cost grows when using closures that capture variables in Kotlin.
We want to see how the number of operations changes as input size grows when closures remember variables.
Analyze the time complexity of the following code snippet.
fun createFunctions(n: Int): List<() -> Int> {
val funcs = mutableListOf<() -> Int>()
for (i in 0 until n) {
val capturedI = i
funcs.add { capturedI * 2 } // closure captures capturedI
}
return funcs
}
fun main() {
val functions = createFunctions(5)
functions.forEach { println(it()) }
}
This code creates a list of functions, each capturing the loop variable i.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: A loop runs
ntimes to createnclosures. - How many times: The loop runs once for each number from 0 to
n-1.
Each time n grows, the loop runs more times, creating more closures.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | 10 closures created |
| 100 | 100 closures created |
| 1000 | 1000 closures created |
Pattern observation: The work grows directly with n. Double n, double the work.
Time Complexity: O(n)
This means the time to create all closures grows in a straight line with the number of closures you want.
[X] Wrong: "Closures run instantly and don't add to time because they just remember variables."
[OK] Correct: Creating each closure takes time because it stores the current variable value. More closures mean more work.
Understanding how closures capture variables and how that affects time helps you explain how your code scales when using functions inside loops.
"What if the closure captured a variable that changes inside the loop instead of the loop variable itself? How would that affect time complexity?"
Practice
Solution
Step 1: Understand closure behavior
A closure is a function that keeps access to variables from where it was created, even if that place no longer exists.Step 2: Apply to Kotlin closures
In Kotlin, lambdas capture variables from the surrounding scope and can use them later.Final Answer:
It remembers and can use those variables even after the outer function ends. -> Option DQuick Check:
Closure remembers and can use variables even after outer ends = C [OK]
- Thinking closures delete outside variables
- Believing closures only copy variables without access
- Assuming closures ignore outside variables
count in Kotlin?Solution
Step 1: Identify lambda syntax capturing external variable
In Kotlin, a lambda can access variables from outside without parameters by just using them inside curly braces.Step 2: Check each option
val lambda = { println(count) } correctly usescountfrom outside. val lambda = (count) -> println(count) tries to declare a parameter but syntax is wrong. val lambda = fun(count) { println(count) } uses fun keyword incorrectly. val lambda = { count -> println() } declares a parameter but does not use it properly.Final Answer:
val lambda = { println(count) } -> Option BQuick Check:
Lambda uses outside variable directly = A [OK]
- Trying to declare external variables as lambda parameters
- Using incorrect lambda syntax with fun keyword
- Not referencing the variable inside the lambda body
fun main() {
var x = 5
val closure = { x += 1; println(x) }
closure()
closure()
println(x)
}Solution
Step 1: Trace the closure calls and variable changes
Initially, x = 5. First closure call increments x to 6 and prints 6. Second call increments x to 7 and prints 7.Step 2: Print final value of x
After two increments, x is 7, so printing x outputs 7.Final Answer:
6\n7\n7 -> Option AQuick Check:
Closure increments x twice, final x = 7 [OK]
- Assuming closure uses a copy of x, not the original
- Forgetting x increments on each closure call
- Confusing printed values with initial x
fun main() {
val funcs = mutableListOf<() -> Unit>()
for (i in 1..3) {
funcs.add { println(i) }
}
funcs.forEach { it() }
}Solution
Step 1: Understand variable capture in Kotlin loops
Kotlin captures the loop variableicorrectly for each lambda, so each lambda remembers its ownivalue.Step 2: Check output of lambdas
When calling each lambda, they print 1, 2, and 3 respectively, no error occurs.Final Answer:
Lambdas print 1, 2, 3 correctly -> Option CQuick Check:
Kotlin captures loop vars per iteration = B [OK]
- Assuming all lambdas print the last loop value
- Expecting syntax or runtime errors for capturing loop vars
- Confusing Kotlin behavior with other languages like JavaScript
val funcs = mutableListOf<() -> Unit>()
for (i in 1..3) {
// What to do here?
}
funcs.forEach { it() }Solution
Step 1: Understand variable capture in Kotlin for loops
In Kotlin, lambdas added inside a for (i in 1..3) capture the i from their iteration correctly.Step 2: Check each snippet
funcs.add { println(i) } prints 1 then 2 then 3. The snippet with val x = i + 1; funcs.add { println(x) } prints 2 3 4. funcs.add { println(i + 1) } prints 2 3 4. val x = i; funcs.add { println(x + 1) } prints 2 3 4.Final Answer:
for (i in 1..3) { funcs.add { println(i) } } -> Option AQuick Check:
Direct println(i) in for loop lambda = B [OK]
- Declaring x = i + 1 and printing x (prints 2 3 4)
- Printing i + 1 directly (prints 2 3 4)
- Copying to x = i but printing x + 1 (prints 2 3 4)
Ready to prove it?
Pass the test and this pattern moves unknown
