skip to content

What does the `by` keyword do in a property declaration like `val name by delegate`, and how is reading that property different from a normal property?

level: juniorimportance: must knowfreq 70%

answer

  1. `by` = property has no backing field
  2. read -> getValue(thisRef, property)
  3. write -> setValue(thisRef, property, value)
  4. val needs getValue; var needs both
  5. property arg is a KProperty with .name

basics

~10 s

by hands control of a property over to another object. Instead of storing the value itself, reading or writing the property calls functions on that other object, which decides what to return or do.

solid answer

~40 s

`val/var name by delegate` is property delegation: the property has no backing field of its own. Every read is rewritten by the compiler into `delegate.getValue(thisRef, property)`, and for a `var`, every write into `delegate.setValue(thisRef, property, value)`. The delegate object supplies those operator functions and decides the actual behavior — caching, lazy init, storing in a map, etc. The point is to reuse a single piece of access logic across many properties without copying boilerplate getters/setters. A `val` only needs `getValue`; a `var` needs both. This is a compile-time transformation, so there is no reflection cost on each access; the `property` argument carries metadata about the declared property.

code

kotlin · 8 lines
kotlin
class Echo {
    operator fun getValue(thisRef: Any?, property: KProperty<*>): String =
        "value of ${property.name}"
}

val message by Echo()
// reading `message` calls Echo.getValue(null, ::message)
// => "value of message"

go deeper

for a junior

Knows by forwards reads/writes to a delegate object and that the delegate decides behavior.

for a middle

Can name getValue/setValue and the thisRef/property arguments precisely and the val-vs-var rule.

for a senior

Explains the compile-time desugaring, the synthetic delegate field, and zero per-access reflection cost.

for a principal

Frames delegation as a reuse mechanism for cross-cutting access logic and discusses tradeoffs vs explicit getters.

## What property delegation is Normally a Kotlin property stores its value in a hidden **backing field**, and reading it just returns that field. **Property delegation** replaces that storage-and-access logic with a separate object — the **delegate** — declared after the `by` keyword: ```kotlin val greeting by SomeDelegate() ``` The property `greeting` no longer has a backing field. Instead, the compiler routes access through the delegate. ## How reads and writes are rewritten The compiler desugars delegated access into operator-function calls on the delegate: - Reading `greeting` becomes `delegate.getValue(thisRef, property)`. - For a `var`, writing `greeting = x` becomes `delegate.setValue(thisRef, property, x)`. The delegate is stored in a synthetic field (e.g. `greeting$delegate`). The two arguments matter: - **`thisRef`** — the object that owns the property (or `null` for a top-level property). Lets the delegate behave differently per owner. - **`property`** — a `KProperty<*>` describing the declared property: its `name`, return type, etc. A delegate can use `property.name` (e.g. to look up a key in a map). ## `val` vs `var` - A read-only `val` requires only `getValue`. - A mutable `var` requires both `getValue` and `setValue`. If the delegate lacks the needed function with the right signature, the code does not compile. ## Why use it Delegation lets you write access logic once and reuse it across many properties — lazy initialization, observing changes, reading from a `Map`, etc. — instead of hand-writing custom getters/setters everywhere. Key point: this is a **compile-time** transformation, not runtime reflection on every call, so it is cheap.

  • Does a delegated property have a backing field?
    No backing field for the value; the compiler creates a hidden field that holds the delegate instance instead.
  • What is the second parameter passed to getValue?
    A KProperty<*> describing the delegated property — its name, type and other metadata.

Like forwarding your mail to an assistant: instead of you handling each letter, the assistant (delegate) receives every request and decides what to do.

saying these in an interview costs you the question

  • Saying the property still stores its own value in a normal backing field
  • Thinking `by` does reflection on every access (it is a compile-time rewrite)
  • Claiming a `val` delegate needs a setValue function
  • Confusing property delegation with class/interface delegation (`class A : B by b`)

context