Let function behavior and use cases in Kotlin - Time & Space Complexity
Let's explore how the time cost changes when using Kotlin's let function.
We want to see how the number of steps grows as input changes when let is used.
Analyze the time complexity of the following code snippet.
val numbers = listOf(1, 2, 3, 4, 5)
numbers.map { it * 2 }
.let { doubled ->
doubled.filter { it > 5 }
}
This code doubles each number in a list, then uses let to filter numbers greater than 5.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Traversing the list twice -- once to double each number, once to filter.
- How many times: Each traversal goes through all elements once.
As the list size grows, the code does two full passes over the data.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 20 steps (2 passes x 10 items) |
| 100 | About 200 steps (2 passes x 100 items) |
| 1000 | About 2000 steps (2 passes x 1000 items) |
Pattern observation: The work grows directly with the number of items, doubling the effort because of two passes.
Time Complexity: O(n)
This means the time to finish grows in a straight line with the list size, even with let wrapping the second step.
[X] Wrong: "Using let adds extra loops or slows down the code a lot."
[OK] Correct: let just passes the result to a block; it doesn't add loops itself. The main cost comes from the operations inside, not from let.
Understanding how let affects time helps you explain your code clearly and shows you know how Kotlin handles data flow efficiently.
"What if we replaced filter inside let with another map? How would the time complexity change?"
Practice
let function primarily do when called on an object?Solution
Step 1: Understand the purpose of
Theletletfunction takes the object it is called on and passes it as an argument to a block of code.Step 2: Identify the return value of
The result of the block insideletletis returned as the final value of theletcall.Final Answer:
Executes a block of code with the object as its argument and returns the block's result -> Option BQuick Check:
letruns block and returns result [OK]
- Thinking let creates a new object
- Assuming let deletes the object
- Confusing let with toString conversion
let on a nullable variable name to print it only if it's not null?Solution
Step 1: Recognize nullable safe call usage
To safely callletonly whennameis not null, use the safe call operator?..Step 2: Check syntax correctness
name?.let { println(it) }runs the block only ifnameis not null, printing the value.Final Answer:
name?.let { println(it) } -> Option AQuick Check:
Safe call with let = name?.let { ... } [OK]
- Using let without safe call on nullable variable
- Incorrect syntax like let(name) or let? after variable
- Forgetting the safe call operator
val number = 5
val result = number.let { it * 2 }
println(result)Solution
Step 1: Understand the
The variableletblock executionnumberis 5. Theletblock multipliesit(which is 5) by 2.Step 2: Calculate the result and print
The expressionit * 2evaluates to 10, which is assigned toresultand printed.Final Answer:
10 -> Option AQuick Check:
5 * 2 = 10 [OK]
- Thinking let returns original object
- Confusing it with string output
- Expecting syntax error due to block
let:
val text: String? = null
text.let { println(it.length) }Solution
Step 1: Analyze nullable variable usage
The variabletextis nullable and assignednull. Callingletdirectly runs the block even iftextis null.Step 2: Understand runtime behavior
Inside the block,it.lengthis accessed. Sinceitis null, this causes aNullPointerExceptionat runtime.Final Answer:
NullPointerException at runtime -> Option DQuick Check:
Accessing length on null causes runtime error [OK]
- Assuming let skips block if null without safe call
- Expecting compile error instead of runtime error
- Thinking it prints 'null' string
val numbers: List<Int>? = listOf(1, 2, 3), how can you use let to safely calculate and print the sum only if the list is not null and not empty?Solution
Step 1: Use safe call to handle null list
Sincenumbersis nullable, use?.letto run code only if it's not null.Step 2: Check for empty list inside let block
Inside the block, checkit.isNotEmpty()to ensure the list has elements before summing.Step 3: Print sum only if conditions met
If the list is not empty, print the sum usingprintln(it.sum()).Final Answer:
numbers?.let { if (it.isNotEmpty()) println(it.sum()) } -> Option CQuick Check:
Safe call + empty check + sum print = numbers?.let { if (it.isNotEmpty()) println(it.sum()) } [OK]
- Not using safe call on nullable list
- Skipping empty check causing wrong output
- Using let without safe call causing runtime error
Ready to prove it?
Pass the test and this pattern moves unknown
