Kotlin data vs open class
Tags: kotlin
Published: 2019-12-20 10:19:48

---
title: Kotlin data vs open class
published: true
date: 2018-03-29 19:45:19 UTC
tags: kotlin
canonical_url: https://www.droidship.com/posts/data_vs_open_class/
---

## The Kotlin _data_ class

One of the many handy features that the Kotlin language offers is the _data_ keyword. When we declare a class with the _data_ keyword the compiler implements the _equals(Object o)_,_hashCode()_ and _toString()_ methods, thus saving us from the trouble to do it manually. The [official documentation](https://kotlinlang.org/docs/reference/data-classes.html) provides comprehensive examples and nowadays it has become a widely known language feature, so an example can be left outside of the scope of this post.

## All classes in Kotlin are by default _final_

Another thing that Kotlin does behind the scenes is to compile every class that you declare as _final_, unless you add the _open_ keyword to it. We can see how the language is influenced from _Effective Java 2nd Edition_(Edition 3 is out as well!). More specifically, items 16 and 17 state the following:

> Item 16: Favor composition over inheritance
> 
> Item 17: Design and document for inheritance or else prohibit it

## A clash between keyword definitions

This is a very nice feature of the language, as it tries to protect us from the various perils of improper use of inheritance, as it is described in the book. Unfortunately, things begin to become messy when you try to declare a class both open and data. The compiler will complain that a data class cannot be at the same time open, giving us an error.

Let’s stop for a moment and consider why the architects of the language decided to impose such an obstacle. First of all, we will try to remember some wise words from the _Growing object-oriented systems, driven by tests_ book from Steve Freeman and Nat Pryce. Chapter 2 presents a distinction between _values_ and _objects_. _Objects_ communicate between each other by sending messages and have some specific behavior depending on their state. If their state changes, so does their behavior. On the other hand _values_ - to paraphrase - are just bags of data, used for computations.

Now that the definition and distinction between _objects_ and _values_ is clear, we can see that it does makes sense for Kotlin to impose such rules when using the _data_ and _open_ keywords. A _data_ class is a _value_, holding only - preferably immutable - data without behavior. Since it makes sense to extend a class in order to change its behavior and the _data_ class has no behavior, why should we be able to extend it?

Although the reasons for this design decision are quite valid, the imposed restrictions make the transition from Java to Koltin difficult. We may have in our codebase a class that’s a perfect candidate to become a data class, but if for some reason this class is extended by another class, you cannot make that transition instantly, as you have to fix first the fact that the class is extended. The problem becomes even worse when we have a deep nested hierarchy.

## Some scenarios and possible ways to tackle the problem

One way to deal with this, is to check if the class has any fields or not. If it doesn’t have and it just acts as a marker, we could go and delete that class, trace the compiler errors and replace with the parent class. Indeed we can use this technique, provided that child class is not used in any _instanceOf_ checks. In that case the problem becomes even worse especially when the parent class is involved in the _instanceOf_ checks as well. Here we have a behavioural change in the system which we cannot fix just by replacing the check with the parent class, one that is very difficult to change. The sins of the past have finally caught up with us.

Now let’s consider the case where the child class extends the parent just to inherit some or all the fields of the parent and adds its own as well. Then we could try to use some kind of composition depending on the case.

## Final thoughts

Maybe the nastiest of the problems described above is the _instanceOf_ checks. If we could find a way to get past these checks problem, then replacing the children with the parent or passing the parent as a dependency becomes less difficult.

Unfortunately, this post does not provide a final solution, but rather tries to reason with Kotlin’s implementation decisions and explore some thoughts on how to tackle the problems that arise during a Java to Kotlin migration.