Last Updated:

Composition against inheritance in Kotlin

inheritance in Kotlin

Composition over inheritance (and Kotlin) is a small note that well illustrates the principle of the composition of objects and its advantages over inheritance.


Take a look at the following code:

This is a canonical example of inheritance in object-oriented programming. Class Object Grandchild will be able to call methods parentFunctionality() and childFunctionality(). The code is beautiful and wonderful. But imagine what would happen if you greatly complicated this example by adding many new discovered methods to each class and linking them together. At some point, you may find that you override a method that is used by another method, and thus break the functionality of the entire object.

Of course, competent design will help to avoid this problem, but what if the development team consists not only of you alone and there are many classes in the code with code unfamiliar to you?

In fact, in today's world, inheritance is no longer considered the only true way to design an application. In many cases, the principle of composition will be preferable, when instead of a descendant class, a new class is created that does not override the methods of the ancestor, but calls them directly.

The previous code, rewritten using the composition principle, would look like this:


The principle of composition allows not only to avoid elusive bugs, but also simplifies testing (the ancestor class is easy to replace with a fake implementation) and application maintenance (the code becomes more obvious and understandable).

Kotlin contains several tools that can simplify class composition and even force you to use it instead of inheriting. For example, it is because of possible bugs that Kotlin makes classes non-inheritable by default. There is also language-level support for singletons, so that many classes can be quickly formatted as singletons and directly call their methods without having to create a class and maintain a reference to it.

Delegate function lazy also helps to create compositions, or rather minimize possible overhead. In the following code, the object parent will be created only at the time of the first access to it, that is, it will not take up additional memory, if not used at all:

And finally, extension functions that allow you to add new methods to an existing class without having to inherit from it: