skip to content

Custom Getters & Setters

Custom get() and set(value) let a property compute its value or validate assignment, and private set exposes a read-only view while keeping internal mutability. Computed properties with no backing field are the idiom to reach for instead of a getX() function.

part ofKotlinoverview, primer and where to startread it →
on this pageshow

questions

5

What is a computed property in Kotlin, and how do you write one using a custom get()?

level: juniorimportance: must knowfreq 70%

answer

  1. Custom get() = derived value
  2. No 'field' reference => no backing field
  3. Use val, recomputed every read
  4. Property for cheap/pure, function for expensive/params

basics

~10 s

A computed property has no stored value. Each time you read it, a custom get() runs and calculates the result on the fly from other data, instead of returning something saved in memory.

solid answer

~40 s

A computed property is a property whose value is derived on every read by a custom getter rather than stored. You declare it with `val name: T get() = expression`. Because the getter computes the value, Kotlin allocates no backing field (`field`) for it. It behaves like a zero-argument method but reads like a property, which keeps call sites clean (`person.fullName` not `person.fullName()`). Use `val` since there is nothing to store and assign. Common uses: `isEmpty get() = size == 0`, formatting, and aggregating other properties. Compared to a function, a computed property signals 'cheap, side-effect-free derived state'; expensive or parameterized work should stay a function.

code

kotlin · 4 lines
kotlin
class Order(val items: List<Item>) {
    val total: Double
        get() = items.sumOf { it.price }   // computed each read, nothing stored
}

go deeper

for a junior

Can write val area get() = width * height and explain it computes on read with no stored value.

for a middle

Articulates 'no backing field because field is never referenced' and recomputation on every access.

for a senior

Discusses property-vs-function style guidance (cheap/pure vs expensive/params) and lazy caching for hot paths.

for a principal

Frames computed properties as API design: predictable, side-effect-free reads, and the cost contract callers implicitly assume.

## What 'property' means in Kotlin A Kotlin property is a named member you read/write with field-like syntax (`obj.x`). Under the hood the compiler generates a getter (and a setter for `var`). For a normal property like `var x = 0`, the compiler also creates a hidden **backing field** — actual memory that stores the value. ## Computed property = custom get(), no backing field A **computed property** replaces the default getter with your own `get()` that returns a calculated value. Because the getter never refers to the special `field` identifier, the compiler generates **no backing field** — nothing is stored. The value is recomputed on every read. ```kotlin class Rectangle(val width: Int, val height: Int) { val area: Int get() = width * height // recomputed each read, no storage val isSquare: Boolean get() = width == height } ``` Key points: - Use **`val`**, not `var`: there is nothing to assign, so a setter makes no sense. - The getter can be written as an expression body `get() = ...` or a block `get() { ... return ... }`. - It runs **every** time the property is read, so each access re-evaluates the expression. ## Property vs function A computed property is semantically close to a parameterless function. Kotlin style guidance: prefer a **property** when it's cheap, has no side effects, and just describes derived state (e.g. `size`, `isEmpty`, `fullName`). Prefer a **function** when it's expensive, throws, or takes arguments. ```kotlin class Person(val first: String, val last: String) { val fullName: String get() = "$first $last" // property: cheap, pure fun greeting(lang: String) = "..." // function: takes a param } ``` ## Type inference caveat With a custom getter you usually still declare the type explicitly (`val area: Int`). Kotlin can infer it from the getter, but being explicit is the common, readable style.

  • Why use val and not var for a computed property?
    Because there is no stored value to assign; the value is derived from other state. A var would imply a setter, but you cannot meaningfully store into something that has no backing field.
  • Does the getter run once or on every access?
    On every access. If the computation is expensive, cache it (e.g. with `by lazy`) instead of recomputing each read.

Like a spreadsheet formula cell: it stores no number, it recalculates from other cells whenever you look at it.

saying these in an interview costs you the question

  • Claiming a computed property stores its result like a normal field
  • Saying the getter runs only once and is cached automatically
  • Using var for a derived property that has no backing field
  • Confusing it with a Java field plus getter method

context

open as a page

Explain the `field` identifier in a custom getter/setter. When does a property get a backing field, and what does referencing `field` mean?

level: middleimportance: must knowfreq 65%

basics

~10 s

Inside a custom getter or setter, field is a special name that refers to the property's own storage slot. The compiler only creates that storage if you actually use field, avoiding infinite recursion.

open as a page

What does `private set` do on a property, and how is it different from making the whole property private or using a val?

level: middleimportance: must knowfreq 60%

basics

~10 s

private set lets anyone read the property but only code inside the class change it. The outside world sees a read-only value; the class can still update it internally.

open as a page

Your team debates whether a property may have a custom getter that does I/O or mutates state. What is the contract for getters/setters, and how do you decide between a computed property and a function?

level: seniorimportance: should knowfreq 30%

basics

~10 s

Property reads should feel cheap and harmless. Avoid getters that do slow work, throw, or change state. If it's expensive, has side effects, or takes inputs, make it a function instead.

open as a page

You add a validating custom setter to enforce an invariant, but invalid values still slip in. What are the ways a custom setter can be bypassed, and how do you close the gaps?

level: seniorimportance: should knowfreq 40%

basics

~20 s

A custom setter only runs on normal assignments. The property's own initializer skips it, constructor parameters can skip it, and reflection ignores it. To truly enforce a rule, validate in the constructor or init block too.

open as a page