Home > Software engineering >  JvmField can only be applied to final property. This warning will become an error in further release
JvmField can only be applied to final property. This warning will become an error in further release

Time:08-24

Could anyone clarify as to why this is the case?

I understand in which situations we are unable to use the annotation (outlined in the official document) but I don't understand what the potential issues are - given that the earlier versions of Kotlin compiles and works?

CodePudding user response:

"JvmField can only be applied to final properties", in other words, you cannot put JvmField on overridable (or open) properties.

Let's say you wrote the following, and it were allowed:

open class Foo {
    @JvmField
    open val x = 1
}

And not knowing that x is actually a JvmField, someone else, let's say Bob, inherit Foo and try to override x with his own getter:

class Bar: Foo() {
    override val x get() = (10..20).random()
}

Now, I don't have an old version of Kotlin anymore to actually compile this and see what would actually happen here, but I'll use some logic to show that either way, this leads to a confused Bob.

If this code doesn't compile, then it would be quite unexpected for Bob, wouldn't it? Foo has an open property x, yet when he tries to override it, he cannot! Bob is confused.

If this code does compile, what would it compile to? There would be a getX method in the Bar class, which doesn't actually override anything in Foo. Therefore, when Bob does something like

fun main() {
    printFooX(Bar())
}

fun printFooX(foo: Foo) {
    // this compiles to an access to an access to the JVM field "Foo.x"
    // because the compiler doesn't know any better
    println(foo.x)
}

expecting a number between 10 and 20 to be printed, he would actually get 1, and Bob is confused.

So either way, allowing you to put JvmField on overridable properties will cause confusing behaviour such as those described above, so it is better to just not allow it in the first place.

The root of the problem, as you may have realised by now, is that JVM fields, unlike Kotlin properties, are not overridable. Therefore, to make your Kotlin properties into JVM fields, you need to make them not overridable, to prevent "weird things" from happening.


JvmField also can't be applied to properties marked with override, even if it is also marked with final, but that's another story. To learn more, KT-32753 may be a good start.

  • Related