Why can't we override a val property as a var with a get without initialising it?


#1

I have just started to Learn Kotlin. I wonder why we are not able to use a get() method on a overridden val property as a var without initialising it.

open class Foo {
    val y = 21
	open val x: Int
		get() {
			return 10 * y
		}
}
class Bar : Foo() {
	override var x: Int = super.x * 10
		get() {
			return super.x * (super.x * 10)
		}
}
fun main(args: Array<String>) {
	val bar: Bar = Bar()
	println("${bar.x}")
}

If I don’t initialise x in Bar class it gives a compiler error “Property must be initialised”. But when I print Bar.x it prints the value calculated from the overridden getter but not from the initialised one.

Wouldn’t it be proper that we calculate the value of the overridden parameter from initialisation or by the get() method. Anyway the initialised value is not used when it has a get() method.

But when overridden as a val it works without initialisation.


#2

Why do you want to override x as var in that case : setting x will not change behavior at all ! I don’t see why you would not keep x as val.

Do you have another example where you need it ?

In my opinion, overriding property to change a behavior such as in example only means that you have a new property based on x (x square or smthg like that). Globally, I prefer abstract inheritance vs concrete.

abstract class Foo {
    val y = 21
    val x: Int
        get() = 10 * y
    abstract val squareX: Int
}

class Bar : Foo() {
    override val squareX: Int
        get() = x * x * 10
}

fun main(args: Array<String>) {
    val bar = Bar()
    println("${bar.x}")
}

Adding writabilty, in my sense is a bad choice : it breaks encapsulation and here is a non-sense. I don’t see case where it should be useful to have such a feature.


#3

What you’re trying to do here doesn’t make sense.

Foo.x is always 210.

In Bar.x, you introduce another backing field, because you have an initializer and no setter. This backing field is initialized to super.x * 10, so 2100. You can set this backing field by bar.x=2345.

And the custom getter in Bar.x doesn’t use this additional backing field at all, it just returns 210 * 210 * 10. (super.x is always 210 as I wrote above)