Skip to content

2017.10.17 Kotlin Initialization Order Gotcha

Glen K. Peterson edited this page Oct 17, 2017 · 1 revision

I have a simple class whose constructor takes a somewhat unusual parameter:

class InitIssue(reactor: (InitIssue) -> Int) {
    val x: Int = reactor.invoke(this)
    var items : MutableList<String> = mutableListOf()

    fun addStr(s:String):Int {
        println("items: " + items)
        items.add(s)
        return items.size
    }
}

When I call this code like so:

InitIssue{ initIssue:InitIssue -> initIssue.addStr("hi") }

I get

items: null

java.lang.NullPointerException
	at InitIssue.addStr(InitIssue.kt:9)
	at TestManual2$testInitIssue$1.invoke(TestManual2.kt:38)
	at TestManual2$testInitIssue$1.invoke(TestManual2.kt:35)
	at InitIssue.<init>(InitIssue.kt:4)
	at TestManual2.testInitIssue(TestManual2.kt:38)

Switching the declaration order of x and items fixes the issue:

class InitIssue(reactor: (InitIssue) -> Int) {
    var items : MutableList<String> = mutableListOf()
    val x: Int = reactor.invoke(this)

    fun addStr(s:String):Int {
        println("items: " + items)
        items.add(s)
        return items.size
    }
}

Output:

items: []

Why? I think the fields are initialized in order. In the first one, items is not yet initialized when you call reactor.invoke(). In the second, it is. I'm not sure if this can or should be fixed, but it's something to be aware of. In Java, I remembered to use this only at the end of a constructor.

Clone this wiki locally