Found something neat/interesting... I have this s...
# announcements
r
Found something neat/interesting... I have this simple bit of code:
Copy code
sealed class SealedTypes {
    companion object {
        val types = setOf(One, Two, Three)
    }

    object One : SealedTypes()

    object Two : SealedTypes()

    object Three : SealedTypes()
}

class TypeContainer {
    // Whichever type of SealedType this is set to is removed from the types set.
    var theType: SealedTypes = One
}
And a test that doesn't really do much:
Copy code
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
    @Test
    fun test() {
        // uncomment this and the test will not crash
        // SealedTypes.types

        TypeContainer()
        SealedTypes.types.forEach { acceptNonNull(it) }
    }

    fun acceptNonNull(value: SealedTypes) {
        // no-op
    }
}
test()
surprisingly crashes with a NullPointerException:
Copy code
java.lang.NullPointerException: Parameter specified as non-null is null: method kotlin.jvm.internal.Intrinsics.checkNotNullParameter, parameter value
	at com.personal.ktbugtest.ExampleInstrumentedTest.acceptNonNull(Unknown Source:2)
	at com.personal.ktbugtest.ExampleInstrumentedTest.test(ExampleInstrumentedTest.kt:20)
	at java.lang.reflect.Method.invoke(Native Method)
	...
e
order of static initializers in Java is basically whatever order the classes loaded in
with
val types by lazy { setOf(One, Two, Three) }
it won't crash
basically: in the broken case,
TypeContainer
loads
One
loads
SealedTypes
which wants to load
One
,
Two
,
Three
, but doesn't load
One
because it is already in the process of being loaded, so
One.INSTANCE
is still null when
types
is initialized
r
Oh ok, I was still trying to wrap my head around it after your first reply so thanks for further explaining it. Basically
types
is being initialized before
One
is initialized, and therefore we get a
null
reference. Seems unique to the fact that it's a circular reference then.
e
that, and Kotlin trusts its own types so it doesn't check that
One.INSTANCE != null
when constructing the set
👌 1
ideally this would either work or blow up at initialization instead of being created in this unexpected state, but there's no cheap way to do that on the JVM so 🤷 try to avoid this pattern
👍 1