What is the operator fun provideDelegate, and at what moment does it run relative to a delegated property created with by?
answer
- operator fun, called once at delegate creation
- returns the REAL delegate (with getValue/setValue)
- gives KProperty before binding -> name checks
- thisRef + property: KProperty<*> params
- not per-access; runs once
basics
~20 sIt 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.
solid answer
~40 sprovideDelegate is an operator function the compiler invokes at delegate-creation time for a property declared with by. If the right-hand expression's type has an operator fun provideDelegate(thisRef, property), the compiler calls it once and uses its return value as the actual delegate (the object whose getValue/setValue back the property). It runs when the delegate is established: for a member/top-level property that is during the enclosing object's initialization; for a local delegated property at the point the declaration executes. The KProperty<*> argument gives you the property's name and metadata, so you can validate or select a delegate before binding. It does not run on every get/set — only once per property instance.
code
kotlin · 9 linesclass Tag(val value: String) {
operator fun provideDelegate(thisRef: Any?, prop: KProperty<*>): ReadOnlyProperty<Any?, String> {
println("creating delegate for ${prop.name}")
return ReadOnlyProperty { _, _ -> value }
}
}
class Holder { val label: String by Tag("hi") }
// 'creating delegate for label' prints once, when Holder is constructedgo deeper
Knows it is an optional hook that runs once and returns the actual delegate.
Explains the signature, when it fires relative to object init, and that the return value backs getValue/setValue.
Articulates the design intent: pre-binding access to KProperty for validation/selection, and contrasts with lazy first-access checks.
Discusses generated field shape (prop$delegate), local vs member timing, and when to expose this in a library API vs keeping it internal.
## What provideDelegate is `provideDelegate` is an **optional operator function** that sits in front of Kotlin's delegated-property machinery. When you write a property with the `by` keyword, the expression after `by` normally becomes the *delegate* — the object that must expose `getValue` (and `setValue` for `var`). `provideDelegate` lets you insert a step **before** that binding: instead of using the right-hand object directly, the compiler asks it to *provide* the delegate. ## Signature ```kotlin operator fun provideDelegate( thisRef: R, // the object owning the property (or null for top-level) property: KProperty<*> ): ActualDelegate ``` - It must be marked `operator`. - `thisRef` is the receiver/owner of the property (the enclosing instance, or `Nothing?`/`null` for top-level/local). - `property` is a `KProperty<*>` carrying reflection metadata — most importantly `property.name`. - The **return value** is the real delegate, which itself must have `getValue`/`setValue`. ## When it runs It runs **once, at delegate-creation time**, not on every access: - For a **member or top-level** property, that is during initialization of the enclosing object (when the constructor/initializer runs). - For a **local** delegated property, at the point the `by` declaration is executed. After `provideDelegate` returns, the compiler stores the returned object (in a hidden `prop$delegate` field) and routes every subsequent `get`/`set` through *that* object's `getValue`/`setValue`. `provideDelegate` is never called again for that property instance. ## Why it exists The key benefit: you get the `KProperty<*>` (hence the property name and annotations) **before** the delegate is bound. That enables **property-name validation** or **selecting which delegate to use** at creation time, rather than discovering a problem lazily on first access. ```kotlin class ResourceLoader(val id: String) { operator fun provideDelegate(thisRef: Any?, prop: KProperty<*>): ReadOnlyProperty<Any?, String> { require(prop.name.startsWith("res")) { "Property ${prop.name} must start with 'res'" } return ReadOnlyProperty { _, _ -> "loaded:$id" } } } class Screen { val resTitle: String by ResourceLoader("title") // validated at construction } ``` Without `provideDelegate`, the `require` could only fire on first read of `resTitle`. With it, the check happens when `Screen` is constructed.
- Does provideDelegate run on every property read?No. It runs once when the delegate is created (object/declaration initialization). Reads and writes afterward go through the returned delegate's getValue/setValue.
- What must the object returned by provideDelegate provide?getValue for a val, and getValue plus setValue for a var — exactly what a normal delegate must provide.
Like a building manager who, before handing you the key (the delegate), checks your name on the tenant list and may give you a different key than you asked for.
saying these in an interview costs you the question
- Saying provideDelegate runs on every get/set
- Confusing it with getValue/setValue (it returns the delegate, it isn't the accessor)
- Thinking it is mandatory for delegation
- Not knowing it receives a KProperty with the property name