12

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?

Linda Paiste
  • 38,446
  • 6
  • 64
  • 102
Abner Escócio
  • 2,697
  • 2
  • 17
  • 36
  • 3
    You should read that Effective Java item. It describes just how much work designing a class for inheritance requires. An *excruciating* amount of work. Documenting everything that you require of subclasses, and everything you require them not to do. Building at least 3 separate subclasses, to verify that you base class actually is useful (oh, and you can't write those classes yourself; somebody else has to do it, because you will cheat). etc etc etc. – Andy Turner Aug 03 '18 at 21:05
  • 2
    Most classes _should_ be final. Extending them is probably a bad idea. – Louis Wasserman Aug 03 '18 at 21:09
  • @AndyTurner That's a completely invalid take on inheritance and precisely why people fail at OOP and think it's bad. It's not *your* responsibility to make sure the subclasses don't do something, it's *their* responsibility. Your class is just a blueprint for building houses, if someone wants to copy your blueprint but remove the supporting pillar you've drawn, it's *their* fault. A common phrase I like use is *"who are you to tell me what I am allowed to program to my application?"*. You've made a nice blueprint, now let me use it like I want. – Markus Meskanen Jun 25 '23 at 08:27
  • @MarkusMeskanen you should take it up with the person writing the book. It's advice I choose to follow, because I see how it helps; but I am a mere sign here, not a cop. – Andy Turner Jun 25 '23 at 08:51
  • @MarkusMeskanen re the house blueprint analogy: I don't care how you change something, so long as it doesn't affect me. If I'm going to use the building, I do care that the contractor has followed the blueprint; otherwise, it doesn't affect me. Likewise, I care about subclasses passed to my system to work like I expect, so I don't have to handle the case where they don't: I will design the class to constrain the ways for you to break my system. Don't expect me to forgo my safety to make things easier for you. – Andy Turner Jun 25 '23 at 09:10
  • @AndyTurner Yes apologies if it seemed like I was attacking you, I was merely replying to the Effective Java that you happened to quote. What comes to subclasses being passed to your system, surely you're not suggesting that you let strangers freely inject subclasses to your system and then you're worried about safety? Who's actually injecting those subclasses? The person running the application (e.g. you), via plugins. Just like you shouldn't run viruses on your PC, you shouldn't inject malicious plugins either. Again, it's not your responsibility to stop people from writing bad plugins. – Markus Meskanen Jun 25 '23 at 09:48

5 Answers5

10

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.

devLui
  • 379
  • 3
  • 11
  • 2
    There is a difference between immutable instances and immutable classes. While you might avoid a few bad practices, it will prevent reuse; this is true especially when considering scenarios not thought by the original developer, but that could still work if implemented properly – zambotn May 16 '22 at 13:50
5

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.

iCantC
  • 2,852
  • 1
  • 19
  • 34
  • 6
    If you are a S.O.L.I.D. person, this seems to fly in the face of Open for extension. I find final classes very frustrating, especially in libraries. If there is a bug or you want to extend them, it greatly complicates the process. A well written library has extensibility built in, but no one knows what future future holds or how a library may be used. – Dustin Feb 15 '22 at 20:25
  • Closed classes are a result of people trying to protect their classes and prevent others from breaking them, which is simply nonsense. That's like me drawing a blueprint for a house, then trying to prevent others from copying my blueprint and making changes to it. It's not my responsibility to stop them from building a house that's going to break. I've drawn a house blueprint, I can built houses from it, if you want to copy it go ahead, but don't blame me when your house breaks cause you decided to remove the supporting pillars. – Markus Meskanen Jun 25 '23 at 08:25
4

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.

1

Another reason I can think of is final make static dispatching optimisation possible, which means it doesn't need to do method table lookup.

Alex Bin Zhao
  • 398
  • 3
  • 11
-2

make the class final by default could use less memory in the runtime period.

Bingo
  • 1