Interface delegation generates forwarding methods to a delegate object: `class X(private val d: Foo) : Foo by d`. It reduces boilerplate. Limitation: if you want to change behavior, you must explicitly override methods; it’s not “magic inheritance” and doesn’t intercept calls you didn’t override.
interface Logger { fun log(msg: String) }
class ConsoleLogger : Logger {
override fun log(msg: String) = println(msg)
}
class Service(private val logger: Logger) : Logger by logger {
fun work() = log("working")
}
Advanced answer
Deep dive
Expanding on the short answer — what usually matters in practice:
Context (tags): kotlin, delegation, by, oop
JVM: memory (heap/stack), GC, and what drives latency.
Contracts: equals/hashCode/toString, mutability and consequences.
Explain the "why", not just the "what" (intuition + consequences).
Trade-offs: what you gain/lose (time, memory, complexity, risk).
Edge cases: empty inputs, large inputs, invalid inputs, concurrency.
Examples
Here’s an additional example (building on the short answer):
interface Logger { fun log(msg: String) }
class ConsoleLogger : Logger {
override fun log(msg: String) = println(msg)
}
class Service(private val logger: Logger) : Logger by logger {
fun work() = log("working")
}
Common pitfalls
Too generic: no concrete trade-offs or examples.
Mixing average-case and worst-case (e.g., complexity).