Given multiple property initializers and `init` blocks in a class, what determines the order they execute in?
answer
- One combined sequence, not props-then-inits
- Declaration / textual order, top to bottom
- Can only read what was initialized above
- Constructor params bound before the sequence
- Forward reference = compile error or default value
basics
~10 sThey 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 sProperty 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 linesclass 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
Knows the sequence runs top to bottom in declaration order.
Explains that property initializers and init blocks are interleaved in one lexical sequence and reasons about forward references.
Predicts exact output, explains default-value pitfalls, and ties ordering to invariant correctness.
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