In Kotlin, what does it mean to implement an interface 'by' delegating to another object, and why might you prefer that over extending an open base class?
answer
- by = auto-generated forwarding methods
- composition over inheritance
- exposes interface, hides delegate internals
- avoids fragile base class
- delegate captured at construction
basics
~20 sThe 'by' keyword lets a class implement an interface by handing every method call to another object you give it. You reuse behavior by wrapping an object instead of subclassing it, so you don't depend on a parent class's internals.
solid answer
~40 sKotlin class delegation, written `class Wrapper(d: Iface) : Iface by d`, makes the compiler generate forwarding methods for every member of `Iface`, each calling the stored delegate `d`. This is composition: you hold a reference to a collaborator and reuse its behavior, rather than inheriting it. Preferring it over `open` inheritance avoids the fragile base class problem, where overriding methods couple you to the parent's private call sequences. Delegation only exposes the interface contract, not the delegate's implementation, so internal changes can't break you. You can still selectively override any member in the wrapper, and the compiler keeps forwarding the rest. The delegate is captured at construction; only members declared in the delegated interface are forwarded.
code
kotlin · 7 linesinterface Printer { fun print(msg: String) }
class ConsolePrinter : Printer { override fun print(msg: String) = println(msg) }
// Delegation: no boilerplate, reuse without inheritance
class PrefixPrinter(p: Printer) : Printer by p
fun main() { PrefixPrinter(ConsolePrinter()).print("hi") }go deeper
Knows by forwards interface calls to a held object and that it's composition not inheritance.
Can show selective override plus auto-forward, and explain it exposes only the interface.
Frames it as the standard answer to the fragile base class problem and discusses captured-at-construction semantics.
Weighs API-surface implications: delegation keeps coupling to a stable interface contract, aiding evolvability and testability.
## What class delegation is Kotlin has first-class support for the *delegation pattern* (a.k.a. composition) through the `by` keyword. Instead of subclassing, you declare that your class implements an interface and forwards the work to a held object — the *delegate*. ```kotlin interface Repository { fun load(id: Int): String; fun save(v: String) } class LoggingRepository(private val inner: Repository) : Repository by inner { override fun save(v: String) { println("saving $v") inner.save(v) // selectively override, still call through } // load() is auto-forwarded to inner by the compiler } ``` For every member of `Repository` that you do **not** override, the compiler synthesizes a method whose body is `return inner.member(...)`. You write zero boilerplate. ## Inheritance vs delegation - **Inheritance** (`open class Base` + `class Sub : Base()`): `Sub` gains all of `Base`'s implementation and can `override open` members. It creates an *is-a* relationship and a tight coupling to the base. - **Delegation** (`class W(d: I) : I by d`): `W` *has-a* delegate and exposes only the interface `I`. It is *composition over inheritance*. ## The fragile base class problem With inheritance, a subclass can break when the base class changes its **internal** behavior — for example if the base's `addAll` starts calling `add` internally, an override of `add` may run more times than expected. Because delegation forwards only the public interface and never participates in the base's private call sequence, it sidesteps this fragility. ## Key facts - Only the members of the **delegated interface** are forwarded; you can delegate to many interfaces at once. - The delegate expression is evaluated once and **captured at construction**; it does not auto-update. - You delegate to **interfaces**, not to open classes — `by` requires an interface (or a delegate type that supplies the interface). ## Recall Think of `by` as auto-generated forwarding glue that gives you reuse without an `is-a` chain.
- Can you delegate to a concrete open class with `by`?No. `by` delegates an interface to a value of that interface type. You delegate behavior described by an interface, not by extending a class.
- Does `by` generate any runtime reflection?No. The compiler statically generates plain forwarding methods at compile time; there's no reflection cost.
A receptionist (wrapper) forwards calls to the right department (delegate) without doing the department's job or knowing its internals.
saying these in an interview costs you the question
- Saying `by` means subclassing or `extends`
- Claiming delegation copies the delegate's fields/state into the wrapper
- Thinking you must hand-write each forwarding method
- Believing you can delegate a concrete class instead of an interface