Is there any way to initialize the parent class using a child variable?
Something like this:
open class ParentClass {
protected open val example = ""
val valToInitialize = "Hello $example"
fun printValue() {
print(valToInitialize)
}
}
class ChildClass : ParentClass() {
override val example = "World"
}
So the output of
val childClass = ChildClass()
childClass.printValue()
should be
Hello World
CodePudding user response:
Your code works if you change the properties to have getters that return the strings, rather than have them initialised with the strings:
open class ParentClass {
protected open val example get() = ""
val valToInitialize = "Hello $example"
fun printValue() {
print(valToInitialize)
}
}
class ChildClass : ParentClass() {
override val example get() = "World"
}
This is because initialisation happens in the order of "parent -> child", so if your properties are not initialised, but rather computed in the getter, you circumvent the problem.
If you don't actually intend on instantiating any Parent
instances, you can make the parent class and the property abstract
, so that child classes are forced to override it:
abstract class ParentClass {
protected abstract val example: String
...
}
Important: when implementing the property in child classes, avoid using any other instance properties or methods, because when example
is accessed, the parent class might not be fully initialised yet, so the properties may have values you may not expect, and the methods may behave in unexpected ways as a result. (basically this exact question!)
CodePudding user response:
Just you need to
replace val valToInitialize = "Hello $example"
with val valToInitialize : String get() = "Hello $example"
then you will getting solution
CodePudding user response:
To add to Sweeper's answer: this is a consequence of the superclass calling an override-able method (in this case, a property getter) during initialisation, before any subclasses will have been fully initialised.
Doing so is always risky. If you control all the classes involved, and can follow the exact initialisation sequence of them all, then it's possible to make it work — but it's fragile, and apparently-innocuous code changes can break it.
The safest thing would be for the language itself to prevent you calling anything that could be overridden from a constructor (or initialiser or init
block). But that would make some specialised types of initialisation much harder, so the language designers decided to allow it.
However, it does get flagged in IntelliJ:
Accessing non-final property example in constructor
This is a heads-up that you're doing something dangerous, and you might encounter problems such as in this question. Take heed!