skip to content

Delegated Properties

Property delegation lets an object take over a property's get and set, which is how lazy, observable, and map-backed properties work without any special-casing in the language. It is one of Kotlin's most distinctive features.

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

explore

questions

25

What is the exact operator function signature a class must provide so an instance of it can be used as a custom delegate for a read-only `val` property via `by`?

level: juniorimportance: must knowfreq 55%

answer

  1. operator fun getValue(thisRef, property: KProperty<*>): T
  2. var adds setValue(thisRef, property, value)
  3. thisRef = owner, null for top-level
  4. property.name from KProperty
  5. ReadOnlyProperty / ReadWriteProperty interfaces

basics

~10 s

The delegate needs an operator function named getValue that takes the owner object and the property as parameters and returns the value. For a var you also add a setValue.

solid answer

~40 s

For a read-only `val x by delegate`, the delegate type must declare `operator fun getValue(thisRef: R, property: KProperty<*>): T`, where `R` is the owner's type (or `Any?`/a supertype) and `T` is the property type. `thisRef` is the object that owns the property (or `null` for top-level), and `property` is a `KProperty<*>` reflection handle (so you can read `property.name`). The `operator` keyword is mandatory; the compiler rewrites `x` into `delegate.getValue(this, ::x)`. For a `var`, add `operator fun setValue(thisRef: R, property: KProperty<*>, value: T)`. You can either implement these directly or implement the stdlib interface `ReadOnlyProperty<R, T>` / `ReadWriteProperty<R, T>`, which declare exactly these operator functions.

code

kotlin · 11 lines
kotlin
import kotlin.reflect.KProperty

class TrimDelegate {
    private var value = ""
    operator fun getValue(thisRef: Any?, property: KProperty<*>): String = value
    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
        this.value = value.trim()
    }
}

class Form { var input: String by TrimDelegate() }

go deeper

for a junior

States the getValue signature and that var adds setValue; knows operator is required.

for a middle

Explains thisRef vs property, that the convention is structural, and that ReadOnlyProperty/ReadWriteProperty are the stdlib helpers.

for a senior

Discusses the compiler rewrite to getValue(this, ::prop), reuse via Any? thisRef, and when to implement directly vs. via interface.

for a principal

Frames delegation as a structural convention with reflection metadata, weighs API ergonomics (variance in R, out T), and reflective overhead implications.

## What a delegated property is When you write `val name: String by myDelegate`, Kotlin does NOT store the value in a backing field. Instead it stores `myDelegate` and routes every read/write of `name` through operator functions on that delegate object. This is the *delegated property* convention. ## The getValue convention For a read-only `val`, the delegate must provide: ```kotlin operator fun getValue(thisRef: R, property: KProperty<*>): T ``` - `operator` — REQUIRED keyword; it marks the function as part of a Kotlin convention so the compiler will call it implicitly. - `thisRef` — the object that *owns* the property. For a member property it's the enclosing instance; for a top-level property it's `null` (so the type is often `Any?`). Declaring it as a supertype like `Any?` makes the delegate reusable. - `property: KProperty<*>` — a reflection handle to the property being delegated. `KProperty` comes from `kotlin.reflect`. The most common use is `property.name` (the property's source name) for map keys, logging, etc. The `<*>` star projection means "any property type." - return `T` — must be assignable to the property's declared type. The compiler rewrites the read of `name` as `myDelegate.getValue(this, this::name)`. ## var: add setValue For a mutable `var`, the delegate must ALSO declare: ```kotlin operator fun setValue(thisRef: R, property: KProperty<*>, value: T) ``` A write `name = "x"` becomes `myDelegate.setValue(this, this::name, "x")`. ## Two ways to satisfy the convention 1. **Implement the operator functions directly** on any class. No interface needed — the convention is structural. 2. **Implement a stdlib interface**: `ReadOnlyProperty<in R, out T>` (declares `getValue`) or `ReadWriteProperty<in R, T>` (declares `getValue` + `setValue`). These already mark the functions `operator`, so you just override them. ```kotlin class UppercaseDelegate : ReadWriteProperty<Any?, String> { private var stored = "" override fun getValue(thisRef: Any?, property: KProperty<*>): String = stored override fun setValue(thisRef: Any?, property: KProperty<*>, value: String) { stored = value.uppercase() } } class User { var name: String by UppercaseDelegate() } ``` ## Key points - The convention is matched by *signature*, not by implementing a specific interface. - `thisRef` lets the delegate behave differently depending on the owner; `property` exposes metadata like `property.name`. - A local `val` delegated property is allowed too; `thisRef` is then `null`.

  • Why is the `operator` keyword required on getValue/setValue?
    Because delegated properties are a compiler convention; `operator` tells the compiler these functions may be invoked implicitly. Without it the compiler will not recognize the type as a valid delegate and `by` won't compile.
  • What does the `property` parameter give you access to?
    A `KProperty<*>` reflection object — most usefully `property.name`, but also annotations, return type, and visibility metadata about the delegated property.

The delegate is a property's hired manager: every time someone reads or writes the property, the manager (getValue/setValue) is called instead of touching a field directly.

saying these in an interview costs you the question

  • Forgetting the `operator` keyword on getValue/setValue
  • Saying the value is stored in the property's backing field (it isn't; the delegate holds it)
  • Omitting the `property: KProperty<*>` parameter
  • Claiming you MUST implement ReadWriteProperty (the convention is structural, not nominal)
  • Confusing setValue's parameter order (thisRef, property, value)

context

open as a page

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%

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.

open as a page

What does `val x by lazy { ... }` do in Kotlin, and when does the lambda run?

level: juniorimportance: must knowfreq 78%

basics

~10 s

It delays creating a value until the first time you read the property. The block runs once, the result is remembered, and every later read returns that same stored value.

open as a page

What does Delegates.observable do, and how do you use it to run code every time a property changes?

level: juniorimportance: must knowfreq 55%

basics

~20 s

Delegates.observable lets a property call a small function every time you assign it a new value. You give it a starting value and a callback that runs after each change, so you can react to updates.

open as a page

What are the exact required signatures of getValue and setValue for a `var` property delegate, and what is the role of each parameter?

level: middleimportance: must knowfreq 60%

basics

~10 s

getValue takes the owner object and a property-info object and returns the value. setValue takes the owner, the property info, and the new value, and returns nothing. Both must be marked operator.

open as a page

How does Delegates.vetoable differ from observable, and how do you use its return value to reject an assignment?

level: middleimportance: must knowfreq 50%

basics

~10 s

Delegates.vetoable runs a check before storing a new value. Your lambda returns true to accept the change or false to reject it. If you return false, the property keeps its old value.

open as a page

What is the operator fun provideDelegate, and at what moment does it run relative to a delegated property created with by?

level: juniorimportance: should knowfreq 30%

basics

~20 s

It is an optional hook the compiler calls once when a delegated property is set up. Instead of using your object directly as the delegate, Kotlin asks it to hand back the real delegate, so you can check or swap it first.

open as a page

Explain map-backed delegation: how does `val name: String by map` work, what key is used, and how does delegating to a `MutableMap` differ?

level: middleimportance: should knowfreq 42%

basics

~20 s

A property can delegate to a map; reading the property looks it up in the map by the property's own name. With a mutable map, assigning the property writes that key back into the map.

open as a page

Compare implementing a custom delegate by overriding `ReadWriteProperty<R, T>` versus declaring `operator fun getValue/setValue` directly. When would you pick each, and what do the interface's type parameters mean?

level: middleimportance: should knowfreq 45%

basics

~10 s

Both work. The interface gives you a named, reusable type with the right method shapes already declared. Writing the operator functions directly is lighter when you don't need a shared interface type.

open as a page

What information does the `KProperty<*>` argument carry into a delegate, and how is it commonly used? Show how a map-backed delegate uses it.

level: middleimportance: should knowfreq 45%

basics

~10 s

It is a small description of the property being accessed — mainly its name and type. A common use is property.name to look up the right key, so one delegate can serve many properties.

open as a page

Explain the three `LazyThreadSafetyMode` values (SYNCHRONIZED, PUBLICATION, NONE) and when you'd pick each.

level: middleimportance: should knowfreq 58%

basics

~20 s

They control how a lazy value behaves with many threads. SYNCHRONIZED locks so only one thread computes it (the safe default). PUBLICATION may compute in several threads but keeps the first result. NONE has no safety and is for single-thread use only.

open as a page

When would you choose `by lazy` over `lateinit var`, and how do their initialization and threading semantics differ?

level: middleimportance: should knowfreq 64%

basics

~10 s

Use by lazy when the value is read-only and you want it computed automatically the first time it's needed. Use lateinit var when something external assigns the value later, like a framework injecting it.

open as a page

What problem does Delegates.notNull() solve, and how does it behave if you read it before assigning a value?

level: middleimportance: should knowfreq 38%

basics

~10 s

Delegates.notNull() lets you declare a non-null var without giving it a value right away. You assign it later. If you read it before setting it, you get an exception instead of a silent null.

open as a page

Show how the compiler desugars `val x: T by expr` when `expr` has a provideDelegate operator, including the hidden field and the KProperty argument.

level: middleimportance: should knowfreq 28%

basics

~20 s

Kotlin creates a hidden field for the delegate. If provideDelegate exists, it first calls expr.provideDelegate(owner, property) and stores that result in the field. Then every read calls getValue on that stored field, passing the owner and the property metadata.

open as a page

Give a realistic use case where provideDelegate is the right tool, and explain why moving validation into it beats validating inside getValue.

level: middleimportance: should knowfreq 22%

basics

~20 s

Use it when you must check something about the property at setup time, like its name, and want to fail fast when the object is built rather than later on first use. Checking in getValue only fails when the property is first read, which may be much later or never.

open as a page

How can a custom delegate use its `thisRef` and `property: KProperty<*>` parameters? Give a concrete delegate whose behaviour depends on the owner and on the property's name.

level: seniorimportance: should knowfreq 33%

basics

~10 s

thisRef is the object that owns the property, so the delegate can read or notify it. property gives the property's name and metadata, useful for keys, logging, or validation messages.

open as a page

A junior writes a reusable `var`-delegate that stores its value in a single field on the delegate instance, then uses one delegate object across several properties. What breaks, and how do you design a correct reusable custom delegate?

level: seniorimportance: should knowfreq 28%

basics

~20 s

If one delegate object holds a single value field and is shared by several properties, they all read and write the same field, so the properties overwrite each other. Either give each property its own delegate, or key the storage by the property.

open as a page

Explain precisely how the compiler desugars `var p: T by delegateExpr`. What synthetic members are generated, when is delegateExpr evaluated, and what is the per-access cost?

level: seniorimportance: should knowfreq 35%

basics

~20 s

The compiler stores the delegate in a hidden field evaluated once at initialization, then makes the property's getter call getValue and its setter call setValue on that field. There is no extra storage for the value itself.

open as a page

If a `by lazy` initializer throws an exception on first access, what happens on the next access? Does the answer depend on the thread-safety mode?

level: seniorimportance: should knowfreq 34%

basics

~10 s

If the first computation fails with an exception, the value is not stored. The next time you read the property, Kotlin runs the block again and tries to produce the value once more.

open as a page

Explain the internal design behind observable, vetoable, and notNull. How would you build a custom delegate that both validates and reacts?

level: seniorimportance: should knowfreq 25%

basics

~20 s

observable and vetoable share one base class with two hooks: one decides whether to allow a change, the other runs after it. notNull is a separate delegate that throws if read before set. You can subclass the base to both check and react.

open as a page

Can you use `by` delegation on local variables and top-level properties? What does the compiler pass as thisRef in those cases, and what constraints does that place on the delegate's signatures?

level: seniorimportance: nice to knowfreq 25%

basics

~20 s

Yes — delegation works on top-level properties and local variables, not just class members. In those cases there is no owning object, so the delegate receives null as the owner argument, which means the delegate must accept a nullable owner type.

open as a page

How is `by lazy` implemented under the hood, and what runtime/memory cost does it add compared to an eagerly-initialized `val`?

level: seniorimportance: nice to knowfreq 26%

basics

~20 s

Each by lazy property creates a small helper object that holds the block and the computed value. Reading the property goes through that object and checks if the value exists yet, which costs a little more memory and a tiny check on each read.

open as a page

What are the timing and correctness pitfalls of provideDelegate — e.g., touching thisRef state inside it, ordering with other initializers, and the cost of throwing there?

level: seniorimportance: nice to knowfreq 10%

basics

~20 s

It runs while the owning object is still being built, so the object may be only partly initialized. Reading other fields from thisRef can give defaults or nulls. Throwing inside it aborts construction. Keep it side-effect-light and don't rely on later fields.

open as a page

How can provideDelegate select among different delegate implementations at creation time? Sketch an implementation that picks a delegate based on the property's annotations or name.

level: seniorimportance: nice to knowfreq 14%

basics

~20 s

Because provideDelegate returns the real delegate, it can inspect the property and return different delegate objects for different properties. For example, look at the property's name or annotations and return a cached, computed, or read-only delegate accordingly.

open as a page

What are the practical pitfalls and trade-offs of relying on observable/vetoable for state management, and when would you avoid them?

level: principalimportance: nice to knowfreq 18%

basics

~20 s

These delegates are handy for small reactions and validation, but they hide logic in property setters, fail silently on veto, aren't thread-safe by themselves, and don't compose well. For real reactive flows or complex rules, prefer explicit setters or Flow.

open as a page