Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why are Kotlin classes final by default instead of open?

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?

like image 997
Abner Escócio Avatar asked Aug 03 '18 20:08

Abner Escócio


3 Answers

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.

like image 140
devLui Avatar answered Oct 05 '22 23:10

devLui


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.

like image 32
iCantC Avatar answered Oct 06 '22 00:10

iCantC


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.

like image 33
Duncan Green Avatar answered Oct 06 '22 01:10

Duncan Green