skip to content

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