The documentation tells us the following about open
annotation:
The open annotation on a class is the opposite of Java's final: it allows others to inherit from this class. By default, all classes in Kotlin are final, which corresponds to Effective Java, 3rd Edition, Item 19: Design and document for inheritance or else prohibit it.
My classes
class Foo //I can't inherit it
open class Bar //I can inherit it
What is the real motivation to keep all classes final
by default? Is there any gain in performance? Or just it is a design pattern? Why prohibit open
by default?
For me there are two reasons:
First Kotlin takes many ideas from the functional programming world and uses immutability as often as it can to avoid all the known problems with mutation.
So declaring every class "final" by default is (at least for me) similar.
The class cannot be changed or altered (using something like reflection) during the runtime which would make the safetychecks of the Kotlin compiler useless.
So if you want to "mutate" the default implementation of a class you have to mark it as open explicitly.
The second thought which comes to my mind is that inheritance is often missused. Some examples for common traps are explained here
There is the principle "Favor composition over inheritance" as a guideline for better designs. So declaring every class as final by default forces the developer to at least stop for a moment and think about alternative ways to solve the problem instead of using inheritance for the wrong reasons.
But as longe as there are no official statements by the kotlin developers I can only give an opinionated answer.
Kotlin designers were just trying to make sure, everyone follows good practices.
As already documented, designers followed Joshua Bloch's Effective Java where in chapter Classes & Interface one of the principles speaks about
Design and document for inheritance or else prohibit it
It promotes the idea of documenting any Inheritance behaviour explicitly before using it.
So let's say if we have,
class Foo
We (even the non-author of this code) are assured that this class Foo
is closed for any extension and no random class is using it, that too just by seeing its signature. On the contrast, the same cannot be said for Java
classes, where unless declared final
, some dangling subclass can still extend it.
On the other hand,
open class Foo
Just by class signature, we know that this class is open for inheritance and there might be multiple classes overriding its behaviour. As you see inheritance is explicitly documented here.
For those familiar with the 'O' of SOLID, it seems a strange choice. Immutability has nothing to do with inheritance! So marking a class as final in java does nothing to prevent mutation of the state of instances of that class (of course you can mark all the fields (and the fields of the fields!) as final - sigh).
The essence of modularity is to be able to redeploy existing types in new, useful and potentially unanticipated ways. One way to do this is through inheritance. Inheritance and polymorphism (which are not the same thing at all) have fallen from grace in the Java community because adherence to Liskov Substitution Principal (the 'L') is difficult. Large systems that violate Liskov all over the place are harder to reason about. Locking down classes and functions to prevent poor inheritance and overrides is 'throwing the baby out with the bath water'. What you gain in apparent safety you more than lose in modularity and suppleness.
Classes, by default should be Open for Extension.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With