Lazy property delegation in Kotlin - Time & Space Complexity
Let's explore how the time needed to get a lazy property changes as we use it more.
We want to know how the program's work grows when accessing a lazy property multiple times.
Analyze the time complexity of the following code snippet.
class Example {
val lazyValue: String by lazy {
println("Computing the value...")
"Hello"
}
}
fun main() {
val example = Example()
println(example.lazyValue)
println(example.lazyValue)
}
This code defines a lazy property that computes its value only once when first accessed, then returns the stored value on later accesses.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: The lazy block runs once to compute the value.
- How many times: The computation happens only once, but the property is accessed multiple times.
When you access the lazy property the first time, it does the work to create the value. Later accesses just return the saved result quickly.
| Number of Accesses (n) | Approx. Operations |
|---|---|
| 1 | 1 computation + 1 return |
| 10 | 1 computation + 9 returns |
| 1000 | 1 computation + 999 returns |
Pattern observation: The heavy work happens once, then the cost stays very low no matter how many times you access it.
Time Complexity: O(1)
This means accessing the lazy property takes constant time after the first computation, no matter how many times you use it.
[X] Wrong: "The lazy block runs every time I access the property."
[OK] Correct: The lazy block runs only once; after that, the stored value is returned instantly without repeating the work.
Understanding lazy property delegation helps you explain how to save time by doing work only when needed and only once, a useful skill in many coding situations.
"What if the lazy property was accessed from multiple threads at the same time? How would that affect the time complexity?"
Practice
Solution
Step 1: Understand lazy delegation concept
Lazy delegation means the property value is not created when the object is made, but only when the property is accessed for the first time.Step 2: Compare options with this concept
Delays the creation of a property value until it is first accessed matches this behavior exactly. Options A, B, and D describe different behaviors not related to lazy delegation.Final Answer:
Delays the creation of a property value until it is first accessed -> Option BQuick Check:
Lazy property = delayed creation [OK]
- Thinking lazy creates value immediately
- Confusing lazy with caching multiple values
- Assuming lazy deletes values after use
Solution
Step 1: Recall Kotlin lazy syntax
In Kotlin, lazy properties use the syntax: val propertyName by lazy { initializer }.Step 2: Match options with correct syntax
val name by lazy { "John" } matches this exactly. val name = lazy { "John" } assigns lazy delegate but does not use 'by'. lazy val name = "John" uses invalid order. val name = lazy("John") uses wrong function call syntax.Final Answer:
val name by lazy { "John" } -> Option CQuick Check:
Use 'by lazy { }' for lazy property [OK]
- Omitting 'by' keyword
- Using lazy() as a function call incorrectly
- Placing 'lazy' before 'val'
val lazyValue by lazy {
println("Computing...")
10
}
fun main() {
println(lazyValue)
println(lazyValue)
}Solution
Step 1: Understand lazy initialization behavior
The lambda inside lazy runs only once, when the property is first accessed. It prints "Computing..." and returns 10.Step 2: Trace the program output
First println(lazyValue) triggers lazy initialization, printing "Computing..." then 10. Second println(lazyValue) uses cached value, printing only 10.Final Answer:
Computing...\n10\n10 -> Option AQuick Check:
Lazy runs once, then caches value [OK]
- Assuming lazy block runs every access
- Missing that println inside lazy prints once
- Confusing output order
class Example {
val number = lazy { 5 }
}
fun main() {
val e = Example()
println(e.number)
}Solution
Step 1: Check lazy property declaration
The property 'number' is assigned lazy { 5 } directly, but lazy delegation requires 'by lazy' syntax.Step 2: Identify correct syntax
Correct declaration is 'val number by lazy { 5 }'. Without 'by', 'number' is a Lazy<Int> object, not the Int value.Final Answer:
The property 'number' should be declared with 'by lazy', not assigned directly -> Option DQuick Check:
Use 'by lazy' keyword for lazy properties [OK]
- Omitting 'by' keyword
- Confusing lazy delegate type with property type
- Thinking lazy only works outside classes
class Calculator(val input: Int) {
val result by lazy { /* ??? */ }
} Which is the correct way to implement the lazy block?Solution
Step 1: Understand lazy with constructor parameter
The lazy block can access constructor parameters and member functions. Using a member function keeps code clean and reusable.Step 2: Evaluate options
val result by lazy { input * 2 } uses input directly, which works but may duplicate logic. val result by lazy { Calculator(input).compute() } creates a new Calculator inside lazy, causing recursion. val result by lazy { input } just returns input, no computation. val result by lazy { compute() } // where compute() is a member function calls a member function compute(), which can use input and perform heavy work once.Final Answer:
val result by lazy { compute() } // where compute() is a member function -> Option AQuick Check:
Use member function inside lazy for complex computation [OK]
- Creating new instance inside lazy causing recursion
- Using constructor parameter directly without logic
- Returning parameter without computation
Ready to prove it?
Pass the test and this pattern moves unknown
