Delegation Interview Questions
KOTLIN › Types & Classes
Walk me through why you'd reach for class delegation (by) instead of plain inheritance when wrapping a third-party interface implementation.
What a strong answer covers: A strong answer frames by as composition dressed up with inheritance's syntax convenience: you get an interface's full method set forwarded to a held instance without subclassing a concrete class you don't control, which may be final or whose internals you don't want coupled to, and you can override just the one or two methods you actually need while everything else passes through untouched. This avoids the fragile-base-class problem where extending a third-party class ties you to its implementation details and breaks if the library changes them internally.
Tell me about a gotcha you've hit, or would expect, with by lazy on Android: things like which thread-safety mode to pick, or capturing references that outlive their lifecycle.
What a strong answer covers: The most common gotcha is leaving the default SYNCHRONIZED mode on a property that's only ever read from the main thread, paying unnecessary lock overhead on every access after the first, where LazyThreadSafetyMode.NONE is the correct fix once single-threaded access is guaranteed. The other common one is a lazily-initialized property in a Fragment or Activity capturing this or a Context inside its initializer lambda, so the cached instance keeps that Android component alive longer than its lifecycle would otherwise allow, effectively a memory leak disguised as an optimization.
You added by delegation to reduce boilerplate for an interface, then later needed to override one method, but the override was silently ignored in an internal call path within the delegate. Walk me through why, and what's the fix.
What a strong answer covers: This happens because by only forwards the interface's public entry points to the delegate object; if the delegate's own implementation calls another of its methods internally, that call goes through the delegate's original vtable, not through your subclass, so your override is invisible to it, unlike real inheritance where an overridden method is seen by all internal calls via dynamic dispatch. The fix is either to manually override every method that needs the new behavior so it intercepts that internal call path directly, or to abandon delegation there in favor of real inheritance or explicit wrapping where you control every call.