:wave: Hi everyone! The following code compiles, b...
# compiler
j
👋 Hi everyone! The following code compiles, but fail at runtime (Kotlin 2.2.0 on jvm with IntelliJ 2025.2 Beta Community Edition):
Copy code
object Parent {
    val instance = MyObject(Child.childValue)
    val parentValue = "other"

    object Child {
        val childValue = parentValue
    }
}

data class MyObject(
    val value: String,
)

fun main() {
    println(Parent.Child.childValue)
}
Is it an expected behavior? Shouldn't the compilation fail instead? Here is the stacktrace:
Copy code
Exception in thread "main" java.lang.ExceptionInInitializerError
	at Parent$Child.<clinit>(Main.kt:6)
	at MainKt.main(Main.kt:15)
	at MainKt.main(Main.kt)
Caused by: java.lang.NullPointerException: Parameter specified as non-null is null: method MyObject.<init>, parameter value
	at MyObject.<init>(Main.kt)
	at Parent.<clinit>(Main.kt:2)
p
It is expected behaviour. JVM specification for class static members initialization sequence.
p
Effectively, the
Parent
on instantiation triggers the
Child
to be instantiated (via the usage of
Child.childValue
) - at the point of
Child.childValue
being instantiated, the static value for the parent instance hasn't been instantiated and the value of
parentValue
is still null - resulting in that null being stored on the
childValue
and subsequently passed to
MyObject
constructor.
The above is subtly wrong in this case. By referencing
Child
the JVM will attempt to instantiate it, at which point it's
<init>
method will reference
Parent.parentValue
which triggers instantiation of
Parent
.
Parent.<init>
references an already-instantiating
Child
field which has yet to be populated (as the JVM is still instantiating
Parent
from which it will acquire the value to populate on
childValue
) and as such it's still
null
when being passed to
MyObject
)
if you remove the
val instance = MyObject(Child.childValue)
or make it lazy
val instance by lazy { MyObject(Child.childValue) }
it should work
j
Thanks for yours answers 👍