"lateinit var overrides lateinit var"

1.3k Views Asked by At

Let's say I have a setup like so:

abstract class FooTest {

    open lateinit var softAssertions: SoftAssertions

    ... reusable auxiliary functions ...
}
@ExtendWith(SoftAssertionsExtension::class)
class BarTest: FooTest(){

    @InjectSoftAssertions
    override lateinit var softAssertions: SoftAssertions

    ... actual test cases ...
    
}

IntelliJ gives me a very helpful warning for softAssertions in BarTest:

lateinit var overrides lateinit var

Yeeeeeeees ..? Go on, what's your point?

I eventually realised that my lateinit var in FooTest really should be an abstract val, instead - which got rid of the warning - but even so, I'm wondering ... is there something about a lateinit var overriding a lateinit var that I should know but don't and IntelliJ wants to tell me but doesn't?

2

There are 2 best solutions below

0
On BEST ANSWER

The reason is described in the issue which added the inspection:

It seems suspicious that an instance of A2 [BarTest in your case] will have two fields for the single property and the one from A1 [FooTest] remains effectively unused.

...

why do we consider suspicious just a case with lateinit properties? I'd say here that any case where one property with backing field overrides another property with backing field is suspicious.

Properties with backing fields in general can have custom setters, so overriding them can make sense in some situations. On the contrary, lateinit properties never have custom setters, thus overriding them makes the overridden property backing fields always unused.

These two different backing fields also can lead to fun things like 'isInitialized' property of a lateinit variable is false when it is overridden as a var by another class.

It could make sense to add an exception where overriding property has an annotation like in your case.

0
On

Basically it is just warning you, it thinks that this override might not be intentional because it doesn't see anything useful about it. Generally, you can not override a variable, but variables in Kotlin are properties (i.e. they have getters and setters). So technically, you are overriding the getters/setters, but why do you need to do that since you are not changing their implementation.

A good example of property overriding in Kotlin will be when you have:

abstract class FooTest {
    open val softAssertions: SoftAssertions
}

and then

@ExtendWith(SoftAssertionsExtension::class)
class BarTest: FooTest(){

@InjectSoftAssertions
override lateinit var softAssertions: SoftAssertions

... actual test cases ...
}

In this case, you are overriding a val(which has only a getter) by a var(which has both getter and setter).