skip to content

Given multiple property initializers and `init` blocks in a class, what determines the order they execute in?

level: middleimportance: must knowfreq 65%

answer

  1. One combined sequence, not props-then-inits
  2. Declaration / textual order, top to bottom
  3. Can only read what was initialized above
  4. Constructor params bound before the sequence
  5. Forward reference = compile error or default value

basics

~10 s

They run top to bottom in the order they are written in the class body. Property initializers and init blocks share one sequence — whichever appears first runs first.

solid answer

~40 s

Property initializers and `init` blocks are interleaved into a **single initialization sequence** that runs in **declaration (textual) order**, top to bottom. The primary-constructor parameters are available before this sequence starts. A consequence: a property can only be read in `init` (or in a later property initializer) if it was assigned **earlier** in the file. Forward references compile only when the compiler can't prove the property is unread; otherwise you get a compile error or read a default/uninitialized value. This is why ordering matters: if `init` depends on a `val` computed below it, the value isn't there yet. The rule is purely lexical order within the class body, not 'all properties first, then all inits'.

code

kotlin · 6 lines
kotlin
class Order(qty: Int, price: Int) {
    val subtotal = qty * price          // runs 1st
    init { require(subtotal >= 0) }      // runs 2nd, sees subtotal
    val tax = subtotal / 10              // runs 3rd
    init { println("total=${subtotal + tax}") } // runs 4th
}

go deeper

for a junior

Knows the sequence runs top to bottom in declaration order.

for a middle

Explains that property initializers and init blocks are interleaved in one lexical sequence and reasons about forward references.

for a senior

Predicts exact output, explains default-value pitfalls, and ties ordering to invariant correctness.

for a principal

Discusses how ordering interacts with inheritance/overrides and designs classes to avoid order-dependent fragility.

## The single-sequence rule Kotlin treats **property initializers** (the `= ...` on a property) and **`init {}` blocks** as one combined list. During construction they execute **top-to-bottom in the exact order they are written** in the class body. They are *interleaved* — Kotlin does not run all property initializers first and then all init blocks. ```kotlin class Demo(val seed: Int) { val a = seed * 2 // 1 init { println("a=$a") } // 2 -> sees a, prints a=... val b = a + 1 // 3 init { println("b=$b") } // 4 -> sees b } ``` Output order: assign `a`, print `a`, assign `b`, print `b`. ## Why declaration order matters Because execution is lexical, a member can safely read **only what was initialized above it**: ```kotlin class Broken(val x: Int) { init { println(y) } // y not yet initialized! val y = x + 1 } ``` Reading `y` before its initializer runs is a problem. The Kotlin compiler often catches obvious forward references with an error, but in some shapes (especially through overridden members during base-class construction) you can observe a property's **default value** (`0`, `null`) instead. The fix is to declare dependencies **above** their uses. ## Primary-constructor parameters come first Constructor parameters (`seed`, `x` above) are bound **before** the property/init sequence runs, so every initializer and init block can read them. ## Mental model Think of the class body as a script: the compiler concatenates each property initializer and each `init` block, in source order, into the body of the primary constructor. Reordering members reorders execution.

  • If I move an `init` block above the property it reads, what happens?
    It runs before that property is initialized, so it reads an uninitialized/default value or fails to compile due to a forward reference.
  • Are constructor parameters available before all of this?
    Yes — primary-constructor parameters are bound first, so the whole property/init sequence can read them.

It's a recipe read line by line: you can't stir in the sauce on line 3 if you only make it on line 7.

saying these in an interview costs you the question

  • Saying all property initializers run, then all init blocks
  • Claiming order is non-deterministic
  • Thinking you can freely forward-reference any property in init
  • Ignoring that constructor params precede the sequence
  • Believing reordering members has no effect

context