Delegation with by
In this page:
interface InterfaceName {
fun method()
}
class ClassName(impl: InterfaceName) : InterfaceName by impl {
// members forwarded to impl; override any you want to change
}
Delegating an Interface with by
Writing : Interface by someObject after a class header automatically forwards every call to that interface's members to someObject, without writing any forwarding code by hand.
Example: Delegating an Interface with by
// Define an interface `Printer` describing required behavior
interface Printer {
// Define the function `printMessage` taking `message`
fun printMessage(message: String)
}
// Define a class `ConsolePrinter`
class ConsolePrinter : Printer {
override fun printMessage(message: String) {
// Print "Console: $message" to the console, with a trailing newline
println("Console: $message")
}
}
// Define a class `App`
class App(printer: Printer) : Printer by printer
// Entry point: execution of the program starts here
fun main() {
// Declare a read-only variable `app`, set to `App(ConsolePrinter())`
val app = App(ConsolePrinter())
app.printMessage("Hello via delegation")
}
Login to try C/C++/Java/PHP code in the editor
Overriding a Delegated Member
Even when using by to delegate an interface, a class can still override any specific member itself, and that override takes priority over the forwarded implementation.
Example: Overriding a Delegated Member
// Define an interface `Printer` describing required behavior
interface Printer {
// Define the function `printMessage` taking `message`
fun printMessage(message: String)
}
// Define a class `ConsolePrinter`
class ConsolePrinter : Printer {
override fun printMessage(message: String) {
// Print "Console: $message" to the console, with a trailing newline
println("Console: $message")
}
}
// Define a class `LoudApp`
class LoudApp(printer: Printer) : Printer by printer {
override fun printMessage(message: String) {
// Print "LOUD: ${message.toUpperCase()}" to the console, with a trailing newline
println("LOUD: ${message.toUpperCase()}")
}
}
// Entry point: execution of the program starts here
fun main() {
// Declare a read-only variable `app`, set to `LoudApp(ConsolePrinter())`
val app = LoudApp(ConsolePrinter())
app.printMessage("hello")
}
Login to try C/C++/Java/PHP code in the editor
Why Use Delegation
Delegation avoids the boilerplate of manually forwarding every interface member, while still letting a class compose behavior from another object instead of relying purely on inheritance.
Example: Why Use Delegation
// Define an interface `Repository` describing required behavior
interface Repository {
// Define the function `getAll` with no parameters and returning a `List<String>`
fun getAll(): List<String>
}
// Define a class `InMemoryRepository`
class InMemoryRepository(private val items: List<String>) : Repository {
override fun getAll(): List<String> = items
}
// Define a class `CachedRepository`
class CachedRepository(repo: Repository) : Repository by repo
// Entry point: execution of the program starts here
fun main() {
// Declare a read-only variable `repo`, set to `CachedRepository(InMemoryRepository(listOf("a", "b", "c")))`
val repo = CachedRepository(InMemoryRepository(listOf("a", "b", "c")))
// Print `repo.getAll()` to the console, with a trailing newline
println(repo.getAll())
}
Login to try C/C++/Java/PHP code in the editor
Property Delegation with by lazy
The same by keyword is used for property delegation, with lazy { ... } being the most common built-in delegate -- it computes and caches a value only the first time the property is accessed.
Example: Property Delegation with by lazy
val expensiveValue: String by lazy {
// Print "Computing value..." to the console, with a trailing newline
println("Computing value...")
"Computed Result"
}
// Entry point: execution of the program starts here
fun main() {
// Print "Before access" to the console, with a trailing newline
println("Before access")
// Print `expensiveValue` to the console, with a trailing newline
println(expensiveValue)
// Print `expensiveValue` to the console, with a trailing newline
println(expensiveValue)
}
Login to try C/C++/Java/PHP code in the editor
- Reimplementing every method of an interface by hand to forward calls to an internal object, instead of using Kotlin's built-in
bydelegation. - Forgetting that with
by, overriding one specific method in the delegating class still lets the rest be forwarded automatically to the delegate. - Confusing interface delegation (
byafter an interface in a class header) with property delegation (byon a property, likelazy), which are related but different features.
class MyClass(val impl: Interface) : Interface by implforwards every interface member toimplautomatically.- This avoids writing repetitive forwarding methods by hand, a pattern known as the delegation pattern.
- Specific methods can still be overridden in the delegating class, taking priority over the forwarded implementation.
- Property delegation, like
val x by lazy { ... }, is a related but separate use of thebykeyword.
Chapter Quiz — Complete all 7 topics to unlock
0/7 topics done
Complete these topics first: