skip to content

How do you read and write a property's value reflectively using KProperty.get() and the setter, including for member properties?

level: middleimportance: should knowfreq 40%

answer

  1. KProperty1.get(receiver) reads a member property
  2. var -> KMutableProperty -> set(receiver, value)
  3. getter/setter are KFunctions: .call(receiver, value)
  4. Private: isAccessible = true on prop or accessor
  5. KProperty0 = no receiver (top-level/object)

basics

~20 s

Get a KProperty for the field. To read, call get() (passing the receiver object for member properties). To write, the property must be a var (KMutableProperty); call its setter via .setter.call(receiver, newValue) or .set(receiver, newValue).

solid answer

~30 s

A read-only property is a KProperty (KProperty0/1/2 by receiver count); a var is a KMutableProperty exposing set(). For a member property you use KProperty1<T, V>: prop.get(instance) reads, and if it's a KMutableProperty1<T, V> then prop.set(instance, value) writes. You can also go through the accessors directly: prop.getter.call(instance) and prop.setter.call(instance, value) — the getter/setter are themselves KFunctions. Top-level / object properties use KProperty0 (no receiver): prop.get() / prop.set(value). Reading a val reflectively is fine; you can only set() through KMutableProperty. Private or non-accessible backing requires isAccessible = true on the property (or its accessor). kotlin-reflect must be present for member property reflection.

code

kotlin · 13 lines
kotlin
import kotlin.reflect.KMutableProperty1
import kotlin.reflect.full.memberProperties

class Box(var n: Int)

fun main() {
    val b = Box(1)
    val p = Box::class.memberProperties.first { it.name == "n" } as KMutableProperty1<Box, Int>
    println(p.get(b))            // 1
    p.set(b, 7)
    p.setter.call(b, 9)         // via setter KFunction
    println(b.n)                 // 9
}

go deeper

for a junior

Reads a property with get(receiver) and knows var is needed to write.

for a middle

Casts to KMutableProperty1, uses set()/setter.call(), and handles top-level vs member receiver differences.

for a senior

Explains getter/setter as KFunctions, isAccessible scope, and that get() invokes any custom accessor (not the raw field).

for a principal

Builds generic property-mapping/copy utilities, weighs reflective property access cost, and reasons about backing-field vs accessor semantics.

## Property reflection types Kotlin models properties (not just fields) reflectively: - `KProperty0<V>` — no receiver (top-level/object property): `get()`. - `KProperty1<T, V>` — one receiver (member): `get(receiver)`. - `KProperty2<D, E, V>` — two receivers (member extension). - The **mutable** variants `KMutableProperty0/1/2` add `set(...)`. ## Reading ```kotlin import kotlin.reflect.full.memberProperties class Box(var n: Int) val prop = Box::class.memberProperties.first { it.name == "n" } val value = prop.get(Box(5)) // 5 (KProperty1.get(receiver)) ``` You can equivalently call the **getter** KFunction: `prop.getter.call(Box(5))`. ## Writing Only a `var` is mutable. Cast / check for `KMutableProperty1`: ```kotlin import kotlin.reflect.KMutableProperty1 val b = Box(0) val mp = prop as KMutableProperty1<Box, Int> mp.set(b, 42) // direct setter // or: mp.setter.call(b, 99) // via setter KFunction ``` The **setter** is a `KFunction`; `setter.call(receiver, value)` is positional just like any reflective call. ## Accessibility Private properties (or those with private accessors) throw `IllegalCallableAccessException` until you set `isAccessible = true`: ```kotlin prop.isAccessible = true // on the property // or prop.getter.isAccessible = true / prop.setter.isAccessible = true ``` ## Notes - A `val` exposes no `set()` — attempting to cast to `KMutableProperty` and set is a compile/runtime mismatch. - For top-level (`KProperty0`) there is no receiver argument. - `prop.getter`/`prop.setter` are useful when you want a uniform `KFunction` invocation path or to flip `isAccessible` on the accessor specifically. - Requires **kotlin-reflect** for member properties.

  • Why can't you set() a val reflectively?
    A val has no setter, so reflection exposes it only as a KProperty (not KMutableProperty); there is no set() to call. You can still read it with get().
  • What's the difference between prop.get(x) and prop.getter.call(x)?
    They are equivalent for reading; get() is the typed convenience method while getter.call() routes through the accessor as a generic KFunction (handy for flipping isAccessible on the accessor).

saying these in an interview costs you the question

  • Trying to set() a val / KProperty that isn't mutable
  • Omitting the receiver for a KProperty1.get()
  • Forgetting isAccessible for private property reads
  • Confusing KProperty0 (no receiver) with KProperty1
  • Assuming get() bypasses a custom getter — it invokes it

context