Why does an extension property have no backing field, and what does the `field` keyword do (or fail to do) inside one?
answer
- field = backing-field keyword
- Class layout fixed -> no storage to add
- field/initializer = compile error in extension
- Computed view, not state
- Need state? Map or real member
basics
~10 sA backing field is hidden storage attached to an instance. Extensions don't own the class, so they can't add storage. The value must be calculated each time in the getter; you can't use field.
solid answer
~40 sA **backing field** is the per-instance storage a regular property uses, accessed inside accessors via the `field` keyword. Because an extension property is declared outside the receiver's class and the class layout is fixed, Kotlin cannot allocate storage on those instances, so there is **no backing field** and `field` is unavailable (using it is a compile error). The consequence: every access must **compute** a value from the receiver — `get()` returns a derived value and `set()` must push the change into existing receiver state (a mutable method or another property). If you need real per-instance storage you cannot do it with an extension property; people instead use a `Map` keyed by the instance, delegates, or actual member properties. Extension properties are best for **derived/computed views**, not state.
code
kotlin · 6 lines// Illegal — uncommenting any of these fails to compile:
// val String.x: Int get() = field // 'field' not available
// val String.y: Int = 5 // initializer needs backing field
// Legal — purely computed:
val IntArray.middle: Int get() = this[size / 2]go deeper
Knows the getter must compute the value and there's no stored field.
Explains what field is and why it's illegal here; names the compile errors.
Articulates 'computed view vs state' and the external-Map workaround with leak caveats.
Reasons about API design: keeps extensions pure/derived, pushes mutable state to owned types or delegates.
## Backing field, defined For a normal property, the compiler may generate a hidden field on the object to hold the value. Inside the property's `get()`/`set()` you reference that field with the special identifier **`field`** (the "backing field"). Example: ```kotlin class Counter { var count: Int = 0 set(value) { field = value.coerceAtLeast(0) } // 'field' is the storage } ``` ## Why extensions have none An extension property is declared **outside** the receiver class: ```kotlin val String.lastIndex: Int get() = length - 1 ``` `String` is compiled and fixed; Kotlin cannot retroactively add a field to every `String` instance ever created (including ones from Java). With no place to put a value, the language **disallows a backing field entirely**: - `field` inside an extension accessor -> **compile error**. - An initializer (`= ...`) -> **compile error** (it implies a backing field). - So `get()` is mandatory; for `var`, `set()` is mandatory too. ## What you can and can't do ```kotlin // OK: computed (derived) view val <T> List<T>.secondOrNull: T? get() = if (size >= 2) this[1] else null // OK: var that writes through to existing mutable state var StringBuilder.firstChar: Char get() = this[0] set(value) { setCharAt(0, value) } // COMPILE ERROR: no backing field // val String.cached: Int = computeOnce() ``` ## If you truly need state per instance Extension properties can't hold it. Options: - A real **member property** (if you own the class). - A side `Map<Instance, Value>` (watch for memory leaks; consider weak keys). - A **delegated** member property using `by`. ## Takeaway Treat extension properties as **pure, computed accessors** over the receiver's existing data. They are syntactic sugar; the moment you reach for `field` or an initializer, you've hit the boundary of what they support.
- How could you simulate per-instance state that an extension property reads?Store values in an external `Map` keyed by the instance (e.g. an `IdentityHashMap` or weak-key map) and have the getter/setter read/write that map — but mind lifecycle and leaks.
- Is the lack of a backing field a runtime or compile-time restriction?Compile-time: the compiler refuses to generate the field and rejects `field`/initializers in the source.
A backing field is a drawer built into a desk. An extension property is advice written on a post-it on someone else's desk — no drawer of its own to store things in.
saying these in an interview costs you the question
- Thinking `field` works inside an extension property
- Believing the JVM secretly stores the value per instance
- Using an extension property expecting cached/memoized state
- Confusing backing field with backing property pattern