skip to content

When should you reach for an extension property versus an extension function or a real member property? What are the design trade-offs?

level: principalimportance: should knowfreq 25%

answer

  1. Property = cheap noun, no args, no side effects
  2. Function = args / work / side effects / expensive
  3. Member = need storage or polymorphism
  4. Extensions are static + stateless
  5. Don't break the 'property is cheap' contract

basics

~20 s

Use an extension property for a cheap, no-argument, value-like accessor that reads naturally as a noun. Use an extension function when it takes arguments or does real work. Use a real member when you own the class and need stored state.

solid answer

~40 s

Pick an **extension property** when the result is a cheap, side-effect-free, argument-less *attribute* of the receiver that reads as a noun (`list.lastIndex`, `point.magnitude`) — it makes call sites cleaner and matches the JavaBean-style getter convention. Pick an **extension function** when it takes parameters, performs work or I/O, may be expensive, or has side effects — the `()` signals "this does something." Pick a **real member property** when you own the class and need actual per-instance storage (a backing field) or virtual/overridable behavior, since extensions are static and stateless. Key trade-offs: extension properties can't be `private`-member-aware, can't store state, are resolved statically (no polymorphism), and can shadow confusingly; over-using them for expensive computation misleads readers who expect property access to be cheap.

go deeper

for a junior

Knows a property has no parens and a function does; picks by syntax feel.

for a middle

Applies the cheap/no-args/noun heuristic and uses functions for work with arguments.

for a senior

Adds static-resolution, visibility, and 'property = cheap' contract considerations.

for a principal

Reasons about API surface, interop, shadowing hazards, and team-scale consistency when choosing extension vs member.

## The three options | Option | Owns class? | Stores state? | Takes args? | Virtual? | |---|---|---|---|---| | Extension **property** | No | No (no backing field) | No | No (static) | | Extension **function** | No | No | Yes | No (static) | | Real **member property** | Yes | Yes (backing field) | No | Yes (open/override) | ## When an extension property fits Choose it when the value is: - **Derived** purely from the receiver's existing data, - **Cheap** (O(1)-ish, no I/O, no allocation surprises), - **Argument-free**, and - Reads naturally as a **noun/attribute**. ```kotlin val <T> List<T>.lastIndex: Int get() = size - 1 val Point.magnitude: Double get() = sqrt(x*x + y*y) ``` This improves readability — `pt.magnitude` over `magnitudeOf(pt)`. ## When an extension function is better Use a function when it: - Takes **parameters** (`str.padTo(n)`), - Has **side effects** or does **I/O**, - Is potentially **expensive** (the empty `()` warns callers it's a computation/action, whereas property access implies cheap). The **"property = cheap getter"** convention is a real readability contract; violating it (an extension property that hits the network) surprises everyone. ## When a real member is required If you **own** the type and need: - **Stored state** (a backing field / cached value), or - **Polymorphism** (an `open`/`override`able property), ...you must use a member, because extensions are static (no vtable) and stateless (no `field`). ## Cross-cutting trade-offs - **Static resolution**: extension properties bind to the *declared* type, so they don't override and can be shadowed by a same-named member silently — a maintenance hazard. - **Visibility**: they can't see the receiver's `private`/`protected` members, so they only work over the public API. - **Discoverability/interop**: they live on a file class (`FooKt.getX(receiver)`); fine in Kotlin, clunkier from Java. - **API surface creep**: easy to add, so teams can accumulate redundant or conflicting extensions across files. ## Heuristic Noun + cheap + no args + no side effects -> extension property. Otherwise function. Need storage or override -> member.

  • Why is an expensive extension property a code smell?
    Readers assume property access is cheap and side-effect-free; an expensive one (e.g. recomputing or doing I/O each get) violates that expectation and can cause hidden performance problems in loops.
  • Can an extension property override a member property?
    No — extensions are resolved statically and aren't virtual; a member with the same name shadows the extension, with no override relationship.

An extension property is a label you read at a glance; an extension function is a button you press to make something happen. Don't put a button behind a label.

saying these in an interview costs you the question

  • Recommending extension properties for expensive/IO work
  • Claiming they can override or be polymorphic
  • Saying they can access private members of the receiver
  • No awareness of the cheap-getter readability contract

context