Interface delegation using the by operator allows a class to redirect all interface calls to a specific delegate object. This reduces code duplication and implements the composition pattern.
Example:
interface Logger { fun log(message: String) } class ConsoleLogger: Logger { override fun log(message: String) = println("LOG: $message") } class Service(logger: Logger): Logger by logger { fun doWork() { log("Service is working") } } val service = Service(ConsoleLogger()) service.doWork() // LOG: Service is working
Differences from property delegation:
val/var x by ...) applies to a specific property and requires the implementation of the delegate's interface (e.g., ReadWriteProperty).Pros:
Cons:
How does interface delegation (
by) differ from implementing an interface by passing an object through a field?
Answer:
Delegation (via by) automatically implements all interface methods through the delegate object. If you simply store the delegate object as a field and call its methods manually, you need to explicitly implement each interface method — which leads to duplication and errors. Furthermore, delegation via by provides more readability and less boilerplate code:
// Without delegation class Service2(private val logger: Logger): Logger { override fun log(message: String) = logger.log(message) }
Story
In the project, they tried to implement the decorator pattern for the Logger interface manually, forgetting to implement an additional method of the interface that was later added to Logger. The project compiled, but the new functionality did not work, as the implementation was a "dummy". Interface delegation via by would have avoided this error: all new methods are automatically implemented by the delegate.
Story
When delegating an interface via by, the developer overridden one of the interface methods but forgot that the other methods are still routed through the delegate. As a result, part of the functionality worked "non-standardly" — the error was not caught for a long time in the business method logic.
Story
They tried to implement delegation of multiple interfaces with overlapping methods via by, causing a conflict — the compiler began to issue an ambiguity error, and they had to explicitly override the duplicate methods, otherwise, the project would not compile.