Using a property reference's reflection surface, how do you read a name, read a value, and mutate a property — and what types make set available?
answer
- val -> KProperty, var -> KMutableProperty
- .name reads the property's name string
- .get(receiver) reads, .set(receiver, value) writes
- set only exists on Mutable types (compile-time)
- KProperty0 = no receiver, KProperty1 = one receiver
basics
~10 sOn a property reference you can call .name to get the property's name, .get(obj) to read its value, and .set(obj, value) to change it. Only references to var properties (mutable ones) allow .set.
solid answer
~30 sA property reference is a **`KProperty`** object. Read-only (`val`) properties give `KProperty1<T, R>` / `KProperty0<R>` exposing `.name`, `.get(receiver)`, and `.getter`. A `var` upgrades the type to **`KMutableProperty1<T, R>`** / `KMutableProperty0<R>`, adding `.set(receiver, value)` and `.setter`. Example: `User::email.get(user)` reads, `User::age.set(user, 30)` writes (only because `age` is a `var`). `.name` returns the source name `"email"`. The reference also implements the function type, so `User::email` works as `(User) -> String`. Mutating a `val` is impossible because the type is `KProperty`, not `KMutableProperty`, so `.set` doesn't exist at compile time.
code
kotlin · 6 linesclass Box(var label: String)
val ref = Box::label // KMutableProperty1
val b = Box("old")
ref.set(b, "new")
println(ref.get(b)) // new
println(ref.name) // labelgo deeper
Knows .name and .get exist on a property reference.
Maps val/var to KProperty vs KMutableProperty and uses .get/.set/.name correctly.
Explains arity (0 vs 1), compile-time set safety, and getter/setter members.
Connects to serialization/ORM patterns and the kotlin-reflect classpath nuance.
## The KProperty surface Every property reference is an instance of a **`KProperty`** type from `kotlin.reflect`. Which exact subtype you get encodes both the **arity** (how many receivers) and the **mutability** (`val` vs `var`): | Reference | val (read-only) | var (mutable) | |-----------|-----------------|----------------| | In scope `::p` | `KProperty0<R>` | `KMutableProperty0<R>` | | On a type `T::p` | `KProperty1<T, R>` | `KMutableProperty1<T, R>` | ## Reading - **`.name: String`** — the declared name, e.g. `"email"`. Useful for serialization, logging, building DB column names. - **`.get(receiver): R`** — reads the value. `KProperty0` has `.get()` with no args; `KProperty1` has `.get(receiver)`. - Calling the reference like a function (`prop(receiver)`) is equivalent to `.get`. - **`.getter`** — a `KProperty.Getter`, itself a `KFunction`. ## Writing Only the **`KMutableProperty*`** subtypes — produced when the underlying property is a **`var`** — expose: - **`.set(receiver, value)`** (or `.set(value)` for arity-0). - **`.setter`** — a `KMutableProperty.Setter`. A `val` property reference simply has type `KProperty1` (no `.set`), so attempting to mutate is a **compile-time** error, not a runtime one. ```kotlin class User(val email: String, var age: Int) val u = User("[email protected]", 20) val emailRef = User::email // KProperty1<User, String> println(emailRef.name) // "email" println(emailRef.get(u)) // "[email protected]" // emailRef.set(u, ...) // does NOT compile: val val ageRef = User::age // KMutableProperty1<User, Int> ageRef.set(u, 30) // OK: var println(ageRef.get(u)) // 30 ``` ## Bound vs unbound (brief) `User::age` is **unbound** — you pass the receiver to `.get`/`.set`. `u::age` is **bound** to `u`, a `KMutableProperty0`, so you call `.get()` / `.set(value)` with no receiver. (Deep treatment belongs to the bound-vs-unbound topic.) ## Reflection cost Using references as function values is cheap, but full reflection access may require the `kotlin-reflect` artifact on the classpath for some operations; basic `.get`/`.set`/`.name` on member references work without it.
- Why can't you call .set on User::email when email is a val?Because a val yields KProperty1, which has no set member. The setter only exists on KMutableProperty1, produced only for var. It fails at compile time.
- What does .name return for User::email?The string "email" — the property's declared source name.
saying these in an interview costs you the question
- Claiming you can .set a val reference (it won't compile)
- Confusing KProperty0 (no receiver) with KProperty1 (one receiver)
- Thinking .name returns the value rather than the property's name
- Believing .set throws at runtime instead of being a compile error for val