Why open property is initialized in superclass even when it is overrided by a subclass?


#1

I understand the initialization order starts at the super class and goes down to its children. However, it is weird to me that an open property defined by a super class and overrided by its child will be still initialized first at the super class and then reinitialized at the sub class. Ex:

class Parent {
    open val test: String = "PARENT TEST"
}

class Child : Parent {
    override val test: String = "CHILD TEST"
}

Order of initialization will be:

  1. test = “PARENT TEST”
  2. test = “CHILD TEST”

In that simple case it might appear to not be a problem. However, in addition to 2x initialization which already seems weird enough to me, in a real life and more complex scenario, I would not expect the parent to initialize the value at all because it was overrided by its child. The current behavior makes inheritance harder than it should be.

My current solution was to create a “initXYZ()” function for each property I need to override.

class Parent {
    val test: String = initTest()
    protected open fun iniTest() = "PARENT TEST"
}

class Child : Parent {
    override fun iniTest() = "CHILD TEST"
}

Is that a design decision and expected behavior? Any suggestions other than using “init” functions?


#2

First of all, this set of classes actually defines two properties, each with its own backing field. There will be a field in Parent, initialized with the value “PARENT TEST”, and another field in Child, initialized with “CHILD TEST”. If you don’t want that, you can avoid this by defining open val test get() = "PARENT TEST".

Second, the parent doesn’t know whether there’s a child at all. Its constructor is always executed as it’s defined, and then, if there’s a child class, the child constructor is executed.

Can you show a real example where this kind of initialization behavior is a problem?


#3

In that case, the usage of “open” and “override” for property is a bit confusing since it creates another prop in the child. Also, the use of get() is unfortunate knowing that it’ll be executed every time the property is accessed. Imagine for example the property is initialized using some configuration, file or class loader. We do not want to reexecute it every access, but only once at construction time.

What I’m trying to achieve is a parent providing default init behavior while its children should be able to override that. I guess then overriding properties isn’t the way, yet it is not clear to me what’s the real purpose of it.


#4

The purpose of overriding properties is the same as the purpose of overriding methods - to provide different accessor implementation logic in the base class and the derived classes. It’s not to override initialization logic.


#5

I would add a third, that in the parent class, there might already be initialization code that will read the value of the property, before the subclass has a chance to initialize. This would then break, if the initialization in the parent class is skipped.

I’d also like to ask, how does (in your opinion) the analogous situation look like in Java, and doesn’t that have the same double init problem as well?