Why delegation avoids inheritance in Kotlin - Performance Analysis
We want to see how using delegation instead of inheritance affects the time it takes for a program to run.
Specifically, how does the program's work grow when it uses delegation compared to inheritance?
Analyze the time complexity of the following Kotlin code using delegation.
interface Printer {
fun print()
}
class RealPrinter : Printer {
override fun print() {
println("Printing document")
}
}
class DelegatingPrinter(private val printer: Printer) : Printer by printer
fun main() {
val realPrinter = RealPrinter()
val delegatingPrinter = DelegatingPrinter(realPrinter)
delegatingPrinter.print()
}
This code shows a class using delegation to pass print calls to another class instead of inheriting from it.
Look for repeated actions that affect time.
- Primary operation: Calling the
print()method through delegation. - How many times: Each call to
print()is forwarded once to the real printer.
Each print call goes through delegation once, so the work grows directly with how many times print() is called.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | 10 calls forwarded once each |
| 100 | 100 calls forwarded once each |
| 1000 | 1000 calls forwarded once each |
Pattern observation: The number of operations grows directly with the number of calls, no extra repeated work.
Time Complexity: O(n)
This means the time to run grows in a straight line with the number of method calls, without extra overhead from delegation.
[X] Wrong: "Delegation adds a lot of extra work compared to inheritance because it calls methods twice."
[OK] Correct: Delegation forwards calls directly once, so it does not double the work. It just passes the call along efficiently.
Understanding how delegation affects time helps you explain design choices clearly and shows you know how code structure impacts performance.
"What if the delegated method called another delegated method inside? How would that affect the time complexity?"
Practice
Solution
Step 1: Understand inheritance coupling
Inheritance creates a strong link between parent and child classes, making changes harder.Step 2: Understand delegation flexibility
Delegation shares behavior by forwarding calls, avoiding tight coupling and allowing easier changes.Final Answer:
Delegation allows sharing behavior without tightly coupling classes. -> Option CQuick Check:
Delegation avoids tight coupling = A [OK]
- Thinking delegation is faster than inheritance
- Believing Kotlin does not support inheritance
- Confusing delegation with less code requirement
Printer by a class Document?Solution
Step 1: Recall Kotlin delegation syntax
Kotlin usesclass ClassName(...) : Interface by instanceto delegate.Step 2: Match syntax to options
class Document(printer: Printer) : Printer by printer matches the correct Kotlin delegation syntax exactly.Final Answer:
class Document(printer: Printer) : Printer by printer -> Option AQuick Check:
Delegation syntax uses ': Interface by instance' = B [OK]
- Using 'implements' or 'extends' keywords (Java style)
- Placing delegation inside parentheses incorrectly
- Confusing inheritance syntax with delegation
interface Logger {
fun log(msg: String)
}
class ConsoleLogger : Logger {
override fun log(msg: String) {
println("Console: $msg")
}
}
class FileLogger : Logger {
override fun log(msg: String) {
println("File: $msg")
}
}
class Application(logger: Logger) : Logger by logger
fun main() {
val app = Application(ConsoleLogger())
app.log("Start")
}Solution
Step 1: Identify delegated logger instance
The Application class delegates Logger to the passed instance, here ConsoleLogger.Step 2: Trace the log call
Calling app.log("Start") calls ConsoleLogger.log, printing "Console: Start".Final Answer:
Console: Start -> Option BQuick Check:
Delegation calls ConsoleLogger.log = A [OK]
- Assuming FileLogger is used instead of ConsoleLogger
- Expecting Application prefix in output
- Thinking no output occurs without explicit print
interface Worker {
fun work()
}
class Engineer : Worker {
override fun work() {
println("Engineering work")
}
}
class Manager(worker: Worker) : Worker {
override fun work() {
println("Managing")
}
}Solution
Step 1: Check delegation usage
Manager has a Worker parameter but does not delegate using 'by', so delegation is missing.Step 2: Identify correct delegation syntax
To delegate, Manager should declare:class Manager(worker: Worker) : Worker by worker.Final Answer:
Manager should delegate work to Worker using 'by' keyword. -> Option AQuick Check:
Missing 'by' keyword for delegation = D [OK]
- Thinking override is not needed in Engineer
- Believing interfaces can't be implemented
- Assuming constructor parameters are disallowed
Reader and Writer in one class without inheritance. Which Kotlin approach best avoids inheritance problems?Solution
Step 1: Understand multiple inheritance issues
Inheriting from multiple interfaces can cause tight coupling and complexity.Step 2: Use delegation to combine behaviors safely
Delegation allows combining behaviors by forwarding calls to separate instances, avoiding inheritance problems.Final Answer:
Use delegation to both interfaces by passing separate instances. -> Option DQuick Check:
Delegation combines behaviors safely = C [OK]
- Trying multiple inheritance which Kotlin disallows
- Manually copying methods causing code duplication
- Mixing inheritance and manual implementation causing complexity
Ready to prove it?
Pass the test and this pattern moves unknown
