skip to content

Class Delegation by

Writing class X(private val d: Foo) : Foo by d makes the compiler generate every forwarding member for you. The nuance worth knowing is that the delegate's own internal calls do not route back through your overrides.

part ofKotlinoverview, primer and where to startread it →
on this pageshow

questions

5

What does the `by` keyword do when a class declares `class MyList(impl: List<String>) : List<String> by impl`?

level: juniorimportance: must knowfreq 55%

answer

  1. `by impl` = compiler writes the forwarders
  2. Compile-time, no reflection
  3. Decorator pattern, zero boilerplate
  4. Override any member to customize
  5. Delegate is whatever expression follows `by`

basics

~10 s

It makes the class implement the List interface by automatically forwarding every interface method call to the impl object you pass in, so you don't write those methods by hand.

solid answer

~30 s

`by` is Kotlin's class (interface) delegation. Writing `: List<String> by impl` tells the compiler to generate forwarding implementations for every member of `List<String>`, each delegating to the `impl` instance. So `myList.size` calls `impl.size`, `myList.get(0)` calls `impl.get(0)`, etc. You satisfy the interface contract without manually writing dozens of boilerplate methods. The delegate (`impl`) is a constructor parameter here. You can still override any specific member to customize behavior; the generated forwarders cover the rest. This is implemented at compile time — the compiler emits real override methods, not runtime reflection. It's the Decorator/Wrapper pattern made first-class.

code

kotlin · 12 lines
kotlin
interface Printer { fun print(s: String) }

class ConsolePrinter : Printer {
    override fun print(s: String) = println(s)
}

class PrefixPrinter(impl: Printer) : Printer by impl

fun main() {
    val p = PrefixPrinter(ConsolePrinter())
    p.print("hello") // forwarded to ConsolePrinter.print -> prints hello
}

go deeper

for a junior

Knows by impl auto-implements the interface by forwarding to the delegate and removes boilerplate.

for a middle

Explains it's compile-time generated forwarders (no reflection) and that you can selectively override members.

for a senior

Frames it as first-class Decorator/Wrapper, notes delegate accessibility nuances and where it shines vs inheritance.

for a principal

Discusses API-design implications (forwarding fixed at construction, brittleness on interface evolution) and library patterns built on it.

## What `by` means on a class Kotlin lets a class implement an interface by **delegating** the implementation to another object instead of writing the methods yourself. The syntax is: ```kotlin class MyList(impl: List<String>) : List<String> by impl ``` The part `: List<String> by impl` reads as: "this class is a `List<String>`, and its `List<String>` members are provided by the object `impl`." ## What the compiler generates At **compile time** the Kotlin compiler synthesizes an override for **every member of `List<String>`** (`size`, `get`, `isEmpty`, `iterator`, `contains`, etc.). Each generated override simply calls the same member on `impl`. There is **no reflection** and **no runtime proxy** — these are ordinary forwarding methods. Conceptually it is the same as if you typed: ```kotlin class MyList(private val impl: List<String>) : List<String> { override val size get() = impl.size override fun get(index: Int) = impl.get(index) // ...and so on for every member } ``` but the compiler writes all of it for you. ## Why this is useful - **Eliminates boilerplate** when wrapping/decorating an existing implementation. - Implements the **Decorator pattern** as a first-class language feature. - You only write the members you actually want to change. ## Overriding selectively You can override any member; your override wins over the generated forwarder: ```kotlin class LoggingList(impl: List<String>) : List<String> by impl { override fun get(index: Int): String { println("get($index)") return impl.get(index) // 'impl' must be accessible to do this } } ``` ## Key terms - **Delegate**: the object (`impl`) that actually does the work. - **Interface delegation / class delegation**: this `by` feature (distinct from *property* delegation, which also uses `by` but for `val/var`). - **Forwarding**: each generated method just calls the same method on the delegate.

  • Does `by` use runtime reflection or dynamic proxies?
    No. The compiler statically generates forwarding override methods at compile time; it is plain method calls with zero reflection overhead.
  • Can you override one of the delegated members?
    Yes. Any member you explicitly override replaces the generated forwarder for that member; the rest still forward to the delegate.

Like hiring a stand-in who does every part of the job exactly as the original would, while you step in only for the few tasks you care to do differently.

saying these in an interview costs you the question

  • Claiming `by` works for extending classes (it only works for interfaces)
  • Saying it uses reflection or a runtime proxy
  • Confusing it with property delegation (`val x by lazy {}`)
  • Thinking you must implement every interface method yourself anyway
  • Believing the delegate field is always accessible by default

context

open as a page

When you write `class W(impl: Foo) : Foo by impl`, is the `impl` value stored and accessible inside the class? How do you access the delegate if you need it?

level: middleimportance: should knowfreq 35%

basics

~10 s

The compiler stores the delegate in a hidden field, but a plain constructor parameter is not a property, so you can't reference it later. To use it inside the class, declare it as val.

open as a page

In a class using interface delegation, if you both delegate to an object and explicitly override one method, which implementation runs — and does the delegate still see the override?

level: middleimportance: should knowfreq 45%

basics

~10 s

Your explicit override always runs for that method. But the delegate object never knows about your override — if it calls another of its own methods internally, it calls its own version, not yours.

open as a page

Can a class delegate multiple interfaces, each to a different object, with `by`? What happens if two delegated interfaces declare a member with the same signature?

level: seniorimportance: should knowfreq 28%

basics

~10 s

Yes, you can delegate several interfaces, each to its own object. If two of them declare the same method, the compiler forces you to override that method yourself to remove the ambiguity.

open as a page

What are the design limitations and risks of interface delegation via `by` — especially around interface evolution and which members are NOT forwarded?

level: principalimportance: nice to knowfreq 18%

basics

~20 s

by only forwards members declared by the interface. It can't delegate classes, won't auto-forward new collaborators, and the forwarding is fixed at construction. New interface methods get auto-forwarders too, which can silently expose unintended behavior.

open as a page