A `lateinit` block similar to the `init` block but is executed AFTER subclass constructors

The following code is valid Kotlin code:

abstract class A {

    protected lateinit var v: X

    abstract fun f(): X

    class SubA : A() {
        override fun f(): X {
            return SubX()
        }

        init {
            v = f()
        }
    }
}

It defines an abstract class which has a lateinit var field and an abstract method that sets the value of that field. The reason behind this is that that method may be called later again, and its behavior should be defined in the subclasses that extend the original class.

This code is a simplification of a real-world code, and even though it works, I feel like it is messy since the developer of the subclass could choose not to (or forget) to call v = f() inside an init block. And we cannot do that in A either because then it will show a warning that we are calling a non-final method in the constructor. What I propose is the following:

abstract class A {

    private lateinit var v: X

    abstract fun f(): X

    class SubA : A() {
        override fun f(): X {
            return SubX()
        }
    }

    lateinit { // this does not exist
        v = f()
    }
}

The benefits of this is that now the field can be private instead of protected, and the developer does not have to manually call v = f() in each of their subclasses (or the subclasses of their subclasses), and the naming fits with the nomenclature of Kotlin since lateinit is already a keyword and init is already a block. The only difference between an init and a lateinit block would be that the contents of a lateinit block are executed after the subclass constructors, not before like init.

My question is, why isn’t this a thing? Is this already possible with some other syntax that I do not know about? If not, do you think it’s something that should be added to Kotlin? How and where can I make this suggestion so that the developers would most likely see it?

At least to me if feels a little awkward, like you try to create a circular dependency between initialization of both classes. What if SubA during its initialization would use a function of A which in turn would use a value of v? The reason why many languages were designed in a way that the subclass constructor calls parent constructor is because this way the subclass can be sure its base class was fully initialized.

Also, for me using lateinit keyword would be actually confusing. Current lateinit has nothing to do with constructors. You can initialize lateinit var with any logic specific to your application, so lateinit function sounds to me like a function that we plan to invoke by ourselves at a later time after the constructor.

Implementing this functionality might be tricky, because underlying JVM doesn’t support this. It would probably require synthesizing some code and the resulting class might be not very Java-friendly.

With the limited knowledge about your real case, it seems to me like you should really use aggregation here, not inheritance. Then you wouldn’t have this problem in the first place.

4 Likes