androidkotlinhierarchy

Issues with hierarchy in kotlin


I have a TextElement class with a class level variable valled textGravity which is being initialized with default value Element.HorizontalGravity.DEFAULT

In the constructor of TextElement, I'm calling the super constructor of the parent class Element and in that constructor the textGravity variable got his value. I know this is not a good practice, but it's an inherited project with these kind of structure which cannot be changed for now due to more complex parameters I can't explain here.

The problem is that after textGravity being setted in the parent decode method of the parent Element class... the setted value is being loss, because for some reason I don't understand, is reseted to default because this line of the children TextElement class is called again afther the super constructor:

var textGravity = Element.HorizontalGravity.DEFAULT

Why that happens? How is that possible and how can I avoid that?

class TextElement : Element {
    var textGravity = Element.HorizontalGravity.DEFAULT

    constructor(binaryReader: BinaryReader) : super(binaryReader) {
        decode(binaryReader)
    }
}


open class Element {
    constructor(reader: BinaryReader) {
        this.decode(reader)
    }
    private fun decode(reader: BinaryReader) {
        if (this is TextElement) {
            (this as TextElement).textGravity = Element.HorizontalGravity.MIDDLE
        }
    }
}   

Solution

  • The constructor of the superclass will be invoked before property initializers in the subclass. That is unavoidable. It is what allows those property initializers to call functions reliably on the superclass, for example.

    Per your comment, you switched to lateinit var and got rid of the subclass' own property initializer. That will require one of two things to be true:

    1. The superclass always sets that property. It does in your question, but I assume that the real code is more complex than this. πŸ˜€

    2. Or, you need to guard your use of that property using something like ::textGravity.isInitialized, so you do not try to use it if you have not initialized it. For example, I think that you could have an init block after the property declaration/initializer that double-checks that the property was initialized and, if it does not, initializes it.

    As you note in the question, this code is kinda scary overall, and you are stuck with it. Others reading this question in the future (πŸ‘‹πŸ») might try to rework matters so that the superclass is not trying to mess with subclass properties in the superclass constructor this way.