I am trying to understand why the following code produces:
open class Base(open val input: String) {
lateinit var derived: String
init {
derived = input.toUpperCase() // throws!
}
}
class Sub(override val input: String) : Base(input)
When calling this code:
println(Sub("test").derived)
it throws an exception because it toUpperCase inputjumps to during the call null. I find this counter intuitive: pass a nonzero value to the first constructor, but does it allow null in the init block of the superclass?
I think I have a vague idea of what can happen: since it inputserves as both an argument to the constructor and a property, the assignment internally calls this.input, but is thisnot completely initialized yet. This is really strange: in the IntelliJ debugger it inputresolves normally (to the value "test"), but as soon as I call the expression evaluation window and inputmanually check , it is unexpectedly null.
Assuming this is the expected behavior, what do you recommend doing, namely, when do you need to initialize fields obtained from properties of the same class?
UPDATE:
I published two even more concise code snippets that illustrate where the confusion comes from:
https://gist.github.com/mttkay/9fbb0ddf72f471465afc
https://gist.github.com/mttkay/5dc9bde1006b70e1e8ba