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`?
answer
- operator fun getValue(thisRef, property: KProperty<*>): T
- var adds setValue(thisRef, property, value)
- thisRef = owner, null for top-level
- property.name from KProperty
- ReadOnlyProperty / ReadWriteProperty interfaces
basics
~10 sThe 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 sFor 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 linesimport 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
States the getValue signature and that var adds setValue; knows operator is required.
Explains thisRef vs property, that the convention is structural, and that ReadOnlyProperty/ReadWriteProperty are the stdlib helpers.
Discusses the compiler rewrite to getValue(this, ::prop), reuse via Any? thisRef, and when to implement directly vs. via interface.
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)