As Kotlin steadily spreads into the masses more and more Java developers are being exposed to “new” concepts which were actually available in other languages for years now. Algebraic Data Types (ADT for short) is one of these concepts.
What are ADT?
Simply spoken, an ADT is a type which is represented by several other subtypes. Still sounds too complicated? Okay. How about this one?
Wait, isn’t this a Java enum? Yes it is. It also happens to be a very simple example of ADT.
DeliveryStatus is a type which is indeed represented by several other types (in this case
enum entries). But wait, here is more!
Actually, it turns out that when a parcel is dispatched we would also like to know a tracking number.
Here is how an implementation could look like in Java.
Doesn’t look that bad, right? Yet, it is flawed in one important way —
trackingNumber is used only if
DISPATCHED and is
null in every other case. This is tolerable if the amount of such “special” cases is small, but as code evolves more and more such fields emerge.
Kotlin to the rescue
Kotlin helps us to solve this problem by providing
sealed classes. Here is how you would define an ADT in Kotlin.
Let’s see what’s going here.
- We define a
sealedclass. This means that no other class outside of this Kotlin file can extend
DeliveryStatuswhich in turn means that the compiler knows about every possible subtype of
DeliveryStatus. We’ll get to that at a later point.
- We define some types which extend
- We use an
objectif there is no point in having different instances of this type.
Notice that now only
DeliveryStatus.Dispatching contains a tracking number. No other types have to know about it.
That is all great but how do we use our
DeliveryStatus now? One of the ways would be to use
when operator which makes working with ADTs especially convenient.
Important things to notice:
- There is no need to cast
Dispatchedbecause the compiler already knows that.
- We have
returneven though there is no return type specified. That is because every function returns the
- It does not compile.
Wait what? You read it right — it indeed does not compile, but can you guess why?
The reason for compilation error also happen to be another advantage of ADTs. It does not compile because we forgot to specify
Delivered status in our
when clause. Ouch!
Now it works. ADTs are helping you to ensure that when new types are added you handle them properly. But of course you don’t have to do that and if you’ll remove
showDeliveryStatus it will compile just fine even without
In the end
- ADTs are very helpful in cases when you need a single value which represents one of several possible states.
- It is easy to get started. Just write your next class using ADT. No need to change anything in the existing code.
- ADTs are not a replacement for all model classes, just the ones which have subtypes.
enumis still an ADT.
Let us know what you think in the comments!