← Back to Kotlin Course | Chapter 7: Inheritance & Interfaces | Lesson 7 of 7

Delegation with by

The by keyword lets a class say 'for this ability, just forward all the work to this other object I already have', instead of writing the logic itself.

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

markup
interface Printer {
    fun printMessage(message: String)
}

class ConsolePrinter : Printer {
    override fun printMessage(message: String) {
        println("Console: $message")
    }
}

class App(printer: Printer) : Printer by printer

fun main() {
    val app = App(ConsolePrinter())
    app.printMessage("Hello via delegation")
}

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

markup
interface Printer {
    fun printMessage(message: String)
}

class ConsolePrinter : Printer {
    override fun printMessage(message: String) {
        println("Console: $message")
    }
}

class LoudApp(printer: Printer) : Printer by printer {
    override fun printMessage(message: String) {
        println("LOUD: ${message.toUpperCase()}")
    }
}

fun main() {
    val app = LoudApp(ConsolePrinter())
    app.printMessage("hello")
}

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

markup
interface Repository {
    fun getAll(): List<String>
}

class InMemoryRepository(private val items: List<String>) : Repository {
    override fun getAll(): List<String> = items
}

class CachedRepository(repo: Repository) : Repository by repo

fun main() {
    val repo = CachedRepository(InMemoryRepository(listOf("a", "b", "c")))
    println(repo.getAll())
}

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.

Note: Notice "Computing value..." prints only once, even though the property is read twice.

Example: Property Delegation with by lazy

markup
val expensiveValue: String by lazy {
    println("Computing value...")
    "Computed Result"
}

fun main() {
    println("Before access")
    println(expensiveValue)
    println(expensiveValue)
}
Common Mistakes
  1. Reimplementing every method of an interface by hand to forward calls to an internal object, instead of using Kotlin's built-in by delegation.
  2. Forgetting that with by, overriding one specific method in the delegating class still lets the rest be forwarded automatically to the delegate.
  3. Confusing interface delegation (by after an interface in a class header) with property delegation (by on a property, like lazy), which are related but different features.
Chapter Summary
  • class MyClass(val impl: Interface) : Interface by impl forwards every interface member to impl automatically.
  • 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 the by keyword.
🔒

Chapter Quiz — Complete all 7 topics to unlock

0/7 topics done

Complete these topics first:

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.