What is a Kotlin extension property, and how do you declare one (e.g. a `lastIndex` for `String`)?
answer
- val Receiver.name: T get() = ...
- this == receiver instance inside accessor
- No backing field -> must be computed
- var needs get() and set(value)
- No initializer allowed
basics
~10 sAn extension property lets you add a property to an existing type without changing its code. You write it like val String.lastIndex with a custom getter that computes the value.
solid answer
~40 sAn extension property adds a property-like accessor to a type you don't own, using the syntax `val Receiver.name: T get() = ...` (or `var` with a `get()`/`set()`). The part before the dot is the receiver type; inside the accessor, `this` refers to the receiver instance. For example `val String.lastIndex: Int get() = length - 1` lets you call `"abc".lastIndex`. They are resolved statically (by the declared/static type of the expression, not runtime type) and must be top-level or in another class — they cannot truly store state, so the value is always computed in the getter rather than read from a field.
code
kotlin · 6 linesval String.lastIndex: Int
get() = length - 1
fun main() {
println("abc".lastIndex) // 2
}go deeper
Can declare a simple val Type.x get() = ... and use it like a property.
Explains the no-backing-field rule and why an initializer is illegal.
Connects static resolution and top-level placement; knows they can't see private members.
Frames extension properties as a syntactic convenience over static accessors, weighing API discoverability trade-offs.
## What an extension property is Kotlin lets you add **properties** to a type you don't control (a third-party class, a stdlib type, even your own) without editing or subclassing it. The type you extend is called the **receiver type**; the value the call is made on is the **receiver instance**, available as `this` inside the accessor. ## Syntax ```kotlin val String.lastIndex: Int get() = length - 1 // 'this' is the String; 'length' == this.length var StringBuilder.firstChar: Char get() = this[0] set(value) { this.setCharAt(0, value) } ``` - `val` = read-only (only a `get()`). - `var` = read/write (`get()` **and** `set(value)`). - The text before the dot (`String`, `StringBuilder`) is the receiver type. Usage looks exactly like a real property: `"abc".lastIndex` returns `2`. ## Key constraint: no backing field A normal property can store a value in a hidden **backing field** (`field`). An extension property has **no backing field** because the class it extends is fixed and Kotlin cannot add storage to instances it doesn't own. Therefore: - You **must** provide an explicit `get()` (and `set()` for `var`). - You **cannot** write an initializer like `val String.lastIndex = length - 1` — that would need storage. The compiler rejects it. - The value is always **computed** on each access. ## Where they can live They are declared at the **top level** of a file, or inside a class/object (then they have two receivers). They are **not** members of the extended class, so they don't appear in its API and can't access its `private` members. This stays within "what an extension property is and how to declare it" — function-style extensions, nullable/generic receivers, and resolution rules are separate concerns.
- Why can't you write `val String.lastIndex: Int = length - 1`?An initializer requires a backing field to store the value, but extension properties have no backing field, so you must compute it in `get()` instead.
- Can an extension property be a `var`?Yes, if you provide both a `get()` and a `set(value)`; the setter typically delegates to a mutating method on the receiver.
Like a sticky note clipped onto an object: it tells you something computed about the object, but it isn't stored inside the object itself.
saying these in an interview costs you the question
- Claiming extension properties store state in the instance
- Writing an initializer instead of get()/set()
- Saying they become real members of the extended class
- Confusing the receiver type with the return type