skip to content

How do you override a property in Kotlin, and what rules govern overriding a `val` with a `var` or changing its accessor?

level: middleimportance: should knowfreq 55%

answer

  1. `override val` / `override var`
  2. `val` → `var` allowed (adds setter)
  3. `var` → `val` rejected (drops setter)
  4. Override via initializer, getter, or ctor param
  5. `final override` stops further overriding

basics

~10 s

Mark the parent property open, then redeclare it with override val/override var. You may override a val with a var (adding a setter), but not a var with a val.

solid answer

~40 s

Properties override just like functions: the parent declares `open val`/`open var` (or it is abstract/in an interface), and the child writes `override val`/`override var`. A key rule: you can **widen** a `val` to a `var` (the override adds a setter), because a read-only property exposes only a getter and adding a setter does not break the contract. You **cannot** narrow a `var` to a `val` — that would remove the setter callers rely on. You may override a property by supplying a custom getter (and setter for `var`), by giving it an initializer, or even by declaring it as a constructor parameter with `override val`. The override's getter must return the same (or a subtype) type. Like functions, an overriding property is implicitly `open` unless marked `final override`.

code

kotlin · 9 lines
kotlin
open class Base {
    open val state: String = "idle"   // read-only in base
}

class Live : Base() {
    override var state: String = "running"   // OK: val -> var widens
}

// open var x ... -> override val x would FAIL to compile

go deeper

for a junior

Knows you write override val/override var over an open property.

for a middle

States the val→var allowed / var→val forbidden rule and gives a reason.

for a senior

Connects the rule to Liskov substitution and lists override styles (initializer, getter, ctor param).

for a principal

Reasons about API evolution risk of exposing mutable overrides and accessor-contract stability.

## Overriding properties A property is, under the hood, a getter (and for `var`, a setter). Overriding a property means re-supplying those accessors. The mechanics mirror functions: - Parent declares it overridable: `open val`, `open var`, `abstract val/var`, or an interface property. - Child redeclares with the **`override`** modifier. ```kotlin open class Shape { open val sides: Int = 0 open var label: String = "shape" } class Triangle : Shape() { override val sides: Int = 3 // new value override var label: String = "triangle" // override var } ``` ## The `val` → `var` rule The one direction-specific rule everyone is tested on: - **`val` can be overridden by `var`.** A `val` only promises a getter; a `var` adds a setter. Adding capability does not break callers. - **`var` cannot be overridden by `val`.** That would drop a setter callers already depend on, violating the Liskov contract — the compiler rejects it: *"'var'-property cannot be overridden by 'val'-property"*. ## Ways to override a property - **New initializer:** `override val sides = 3`. - **Custom getter:** `override val sides get() = computeSides()`. - **In the primary constructor:** `class T(override val sides: Int) : Shape()` — a constructor parameter can carry `override`. - **`var` with custom accessors:** supply both `get()` and `set(value)`. ## Reaching the parent accessor Use `super.propertyName` to read the inherited getter from within an override, exactly as with functions. ## Type rules The overriding property's type must match or be a subtype (covariant return) of the parent's getter type. You cannot change a `val`'s declared type to an unrelated type. ## Implicit openness An overriding property is itself `open` to further subclasses unless you write `final override val`.

  • Why is overriding a `var` with a `val` forbidden but the reverse allowed?
    A `val` exposes only a getter; widening to `var` adds a setter (extra capability, safe). Narrowing a `var` to `val` removes the setter callers rely on, breaking the contract.
  • Can a constructor parameter override a property?
    Yes — `class T(override val x: Int) : Base()`. A primary-constructor `val`/`var` parameter may carry the `override` modifier.

saying these in an interview costs you the question

  • Claiming you can override a `var` with a `val`
  • Forgetting the parent property must be `open`/abstract
  • Thinking properties cannot be overridden at all
  • Believing the override type can be any unrelated type

context