Hacker News new | ask | show | jobs
by NovaX 1962 days ago
> Kotlin methods are final by default unless marked open, and thus nonpolymorphic dispatch unless through an interface.

This is a language construct and not enforced within the byte code. There have historically been reasons to allow final to be ignored, such as serialization. Instead the JIT will optimize and deoptimize based on runtime behavior, allowing it to cover cases where overriding is designed for but not done so in the actual runtime environment. There was a nice presentation on "truly final fields" at the 2018 language summit [1].

[1] https://www.youtube.com/watch?v=2HfnaXND7-M

1 comments

It may not currently be enforced, but the compiler could enforce it, depending on assumptions, the same way we enforced it on the GWT compiler (of which I'm one of the engineers who worked on it)

With GWT, we had global information, so we could promote methods to static by class hierarchy analysis.

For a Kotlin class, even with dynamic loading, if the class is not marked 'open', final methods not implementing an interface, or private methods, can be converted into static methods.

e.g.

   class A(val x: Int) {
     fun print() = x
   }
can be transformed into

   class A(val x: Int) {
     fun print() = printStatic(x)
     companion object {
       fun printStatic(self: A) = self.x
     }
   }

And any call site with access to the original signature, e.g.

   val a = A()
   println(a.print())

could be rewritten safely as

   val a = A()
   println(A.printStatic(a))

Now, the current Kotlin compiler frontend or backend may not do any of these, but it could.

There's nothing in the compiler language itself that blocks such optimizations, especially if you're willing to limit reflection (as is the case with Kotlin MPP code), or admit a LTO pass.