In this article I will share my thoughts on a specific Kotlin feature that I find absolutely great because it has the potential to “fix” a long standing misconception about object-oriented design.
Data Classes:
Kotlin has this construct named Data Class. Unsurprisingly, this is basically a class that is intended to hold data. An outstanding example of good naming, isn’t it? You might think that I’m being ironic praising the name of this construct, but, in fact, I’m being absolutely serious. Will explain why in a moment.
Before getting to the main discussion, however, I would like to note that the syntax and the way Data Classes are used are completely irrelevant in the context of this article. Yes, I’m perfectly aware of the fact that Data Classes can eliminate considerable amount of code compared to Java. Not relevant and, IMHO, not very important. Even if Data Classes would double the amount of code, this post would still be written in exactly the same way.
Now, back to naming. Why do I find the name of Data Classes so exciting? First of all, it contains the term “data” which suggests that it should be used for data exclusively. Then, this construct is called “Data Class” and not “Data Object”.
The above statements might sound confusing at this point, but don’t worry. They’ll become clear once I express the main idea of this article, which is the true meaning of the term “object”.
In order to do that, however, let’s get back to Java. It will be easier to explain the issue that Data Classes can fix if I start with Java because the confusion about the meaning of “object” is hard-coded in Java at the language level.
Objects in Java:
In my opinion, the worst aspect of Java programming language is the name of Object
class. Yes, not the class itself, but just its name.
As you probably know, any class in Java inherits from Object
class even if it doesn’t extend Object
explicitly. This implicit inheritance provides all Java classes with default implementations of several general methods (e.g. toString()
).
Such an implementation seems quite reasonable in general, but I think that the name of Object
class is the worst aspect of Java because not all sub-classes of Object
represent true OO objects.
I know that this is yet another confusing statement, but, this time, I can attribute it to someone else. Robert “Uncle Bob” Martin stated the following in his Clean Code book :
Mature programmers know that the idea that everything is an object is a myth.
Martin, Robert. Clean Code.
Unfortunately, by naming the implicit base class Object
, this myth was hardcoded into Java at language level.
The name of Object
class misled generations of Java developers to believe that everything is indeed an object and I observe the consequences of this erroneous belief in almost all Java codebases I have a chance to look at.
The reasonable question at this point would be: if something is not an object, then what?
Data/Object Anti-Symmetry:
I shamelessly copied the title of this section from Clean Code because it’s the most accurate title I could think of.
In object-oriented design there are objects and there are data structures. Each has its own use cases, advantages and limitations.
The general rule of thumb is that objects expose behavior, while data structures expose data. This is the basis for the anti-symmetry argument (which is larger in scope in general).
It is very important to fit either object or data structure to specific use cases, but it is even more important not to mix these two responsibilities in a single class. A class that is an object and a data structure at the same time violates Single Responsibility Principle by definition.
I think that a code example will explain it even better.
This interface represents an object because it exposes behavior:
public interface User { void logout(); void sendMessage(String message); }
This interface, despite having the same name, represents a data structure because it exposes data:
public interface User { String getName(); int getAge(); Address getAddress(); }
Both the above interfaces can be valid representations for real users in code. The choice between them should be made according to the role of this class in the larger design context.
However, this is not a valid representation for real users because this interface takes on the responsibilities of both object and data structure:
public interface User { void logout(); void sendMessage(String message); String getName(); int getAge(); Address getAddress(); }
Even though this last representation is invalid in respect to data/object anti-symmetry, most Java codebases I saw use similar representations extensively.
I do not intend to discuss object and data structures in details here and the above overview is by no means extensive. You can read a much deeper explanation in Clean Code or in this outstanding post by Matt Carroll, which is one of my all time favorites.
Edit: thanks to Reddit user lupajz who mentioned another great article on this subject titled Data, objects, and how we’re railroaded into poor design.
In context of our discussion of Kotlin Data Classes, it is enough that you understand that there are object and data structures and that these responsibilities should be segregated.
Data Classes are the Best Kotlin Feature:
Now I can get back to Kotlin Data Classes and explain why I think that this is the best feature of Kotlin.
Since this language construct explicitly geared towards data, it becomes a natural candidate for implementation of data structures.
This is not bullet-proof solution because developers can still screw up and have both object and data structure responsibilities entangled in a single Data Class. However, the sole fact that the language “guides” developers towards clear separation is a huge benefit in my opinion.
In addition, Kotlin doesn’t have Object
as an implicit base class for all other classes. This is also very good because it means that Kotlin, in contrast to Java, won’t mislead developers into believing that “everything is an object”.
However, I think that Kotlin still screwed the “object” part.
For reasons that I can’t understand, Kotlin authors decided to use “object” keyword to designate anonymous classes and Singletons. This will introduce another confusion of terms and will probably mislead some Kotlin developers to believe that the notion of object is restricted to just these use cases.
Still, even with a bit strange approach for “object” keyword, Kotlin is much better in context of data/object anti-symmetry because it has explicit Data Classes and doesn’t promote “everything is an object” mentality.
Conclusion:
As you might have already known or guessed, I’m not participating in Kotlin fan club.
I’m not excited about writing less lines of code, I don’t believe that functional programming will become widespread, I don’t see much use cases for co-routines and I know how to achieve a reasonable null-safety in Java. I also hate the idea of not having checked exceptions.
But there are also many features of Kotlin that I find very good and useful.
Of all these features, Data Classes is the best one in my opinion.
I’m not super excited about reduction in lines of code due to introduction of Data Classes. Instead, I like Data Classes because this language construct has the potential to fix a long standing misconception that “everything is an object”.
Time will tell.
As always, you are welcome to leave your comments and questions below, and consider subscribing to our newsletter if you liked this post.