6 magic sugars that can make your Kotlin codebase happier — Part 1
Syntactic sugar causes cancer of the semicolon. — Alan J. Perlis
We are constantly missing some things. Some of them are more important than the others, but it is never too late to catch up with those. Kotlin language brings tons of new concepts and features to your miserable programming life and it is really hard to use all of them in your daily duties. After almost two years of using Kotlin in production, the language itself can give me joy and satisfaction. How is it possible? Because of its many small sweet sugars 🍰.
In this article, I would like to share with you my favorite Kotlin candies that I discovered when I was in need of writing robust and concise components for Android applications. To make this article more friendly to read I divided it into three parts. In the first part, you will be able to see some cool features of
sealed class and
when() control flow function. Enjoy!
Seal your class with a kiss of “pattern matching”
Recently I had a chance to work with Swift. Not only did I have to review the code, I also had to translate some of the components into Kotlin. The more code I read, the more amazed I was, but the most attractive feature for me were enums 🚀. Unfortunately, Kotlin enums are not very versatile so I had to find a suitable replacement for them: Sealed classes.
Sealed classes are nothing new in the programming world. Actually, the
sealed class is a pretty well-known language concept. Kotlin introduces the
sealed keyword that can be added to a class declaration and used to represent restricted class hierarchies, where a value can have one type from a limited set, but cannot have any other type. Long story short, you can use sealed classes as a replacement for enums and much more.
Let’s examine the following lines of code.
At first glance, this code does nothing except declare a poor inheritance relationship, but after step by step deconstruction it shows astonishing potential. So, what actually does the
sealed keyword add to the Response class? The best way to unmask it is to use the IntelliJ IDEA Kotlin Bytecode tool.
After this super easy transformation, you can start reading the Java representation of your Kotlin code.
As you have probably already guessed, sealed classes are made especially for inheritance, so they are abstract out of the box. But how are they similar to enums? Here is the moment when the Kotlin compiler does you a huge favour by allowing you to use the subclasses of the
Response class as cases of the
when() function. Additionally, Kotlin provides great flexibility where structures that inherit from a
sealed class can be declared as
data or even as an
Not only does it give fully exhaustive expression, it also provides automatic casting so you can use a
Response instance without any additional transformations.
Can you imagine how ugly and complicated it could look without a
sealed feature, or without Kotlin at all? If you have forgotten some of the Java language, use IntelliJ IDEA Kotlin Bytecode once again, but sit tight — it might make you faint.
Summing up, I was delighted to use the
sealed keyword in such cases because it let me shape my Kotlin code in a fashion similar to the Swift version ❤️.
when() function to permute like a boss
As you have already had a chance to see the power of
when() in use with the
sealed classes, I decided to share more of its robust capability with you. Imagine that you have to implement a function that accepts two
enums and produces an immutable state.
enum class Employee describes all roles that can be found in the Company XYZ and
enum class Contract contains all types of an employment contract. Based on these two
enums you should return a correct
SafariBookAccess. Moreover, your function has to produce the state for all permutations of the given
enums. As the first step, let’s prototype the signature of the state-producing function.
Now it is time to define the
SafariBooksAccess structure and because you are already aware of the
sealed keyword, it is a perfect time to use it. It is not necessary to seal
SafariBookAccess but it is a good way to encapsulate different state definitions in different cases of
So what is the main idea behind of the
access() function? Permutation! Let’s permute 👊.
This code is faultless, but can you make it more Kotlin-ish? What would you suggest while doing the day-by-day code review of your colleague’s PR/MR? Your comments can contain something like this:
- Too many
Pairto avoid nesting.
- Change the order of
enumsparameters. Define pair as a
Pair<Contract, Employee>()object to make it more readable.
- Merge duplicated return cases.
- Change to single a expression function.
Now it looks much cleaner and more concise, but Kotlin has some additional sugar that allows you to omit the
Pair definition completely 🐵. Bam!
I hope that you have found this useful, as this construct made my life easier and my Kotlin codebase happier. Unfortunately, it is not possible to use this syntax for triples.
That’s all for the first part, but if you’re still hungry, stay tuned for Part 2. It will be delivered shortly. Cheers!