Kotlin Sealed Classes for the impatient Java buffs
By: Rajath Krishna
Tags: Kotlin, Java, Kotlin Beginners, Sealed Classes, Translation

We are in the world of Kotlin right now and Google strongly advocates its Kotlin first approach and expects all android developers to make the shift to Kotlin but being a Java guy myself I am quire reluctant to embrace Kotlin. I am sure there are a lot of developers like me who are more comfortable with Java than Kotlin.

I tried finding several resources that would make learning Kotlin interesting and after scraping through the “world wide web”, I decided to learn it my way.

That’s when I thought — Why not learn Kotlin through Java? After all Kotlin is designed to interoperate fully with Java, and the JVM version of its standard library depends on the Java Class Library.

With this thought I tried exploring a few Kotlin specific features and one such feature is the Sealed class.

What is a Sealed class?

“ It’s just an enum with swag. ”

“ It’s an ADT — Algebraic Data Type.”

Blah. Blah. Blah

Well we’ll look at the actual definition in a while.

Now, let’s examine Sealed classes in detail.

A sealed class with nested object declaration, inner classes, open classes and data classes probably looks gibberish to all the Java fan boys and girls.

Well what do we do when we can’t understand a language — we look for translations and so let me demystify this and translate it to its Java form.

Let’s look at each component of a sealed class example and see what it translates to.

Sealed class declaration

sealed class Months()

This loosely translates to the following in Java

public abstract class Months {

private Months() {

}

}

So its just an abstract class with a private constructor and what this means is that we cannot instantiate this directly but we can subclass it.

How do we instantiate them then? — Through the subclasses.

So, let’s throw in a class that extends this sealed class.

sealed class Months() {

class January : Months() {

}

}

So what this turns into is

public abstract class Months {

private Months() {

}

public static final class January extends Months {

public January() {

super();

}

}

}

An inner static final class that is inherited from an abstract class.

In other words :- “ it’s a class that can be instantiated without instantiating the outer class and since they are final they can be compared with “==” or “equals()” ”— sounds vaguely similar to enums in Java right?

Now let’s see what happens if I throw in the following inside this sealed class:

An init block — runs when the sealed constructor is invoked by the subclass, A nested inner class, An object — A singleton equivalent in Java, A data class inside the sealed class — A POJO class equivalent in Java and A class which extends the sealed class and is declared in the same file as the sealed class but not as an inner class —You must probably be wondering how this works since the constructor of sealed class is private and how can it be invoked outside it’s scope?

Well, this is a particular speciality in addition to the “when” behaviour that was added to Kotlin.

Now this translates to the below Java code

That’s it — we just translated the seemingly complex Kotlin code to the simpler Java code.

How is it different from an Enum?

The constants in an enum can have only a single instance.

For example :- You cannot do the following in an enum

enum class Months private constructor(var type: String){

January("January"),

February(2)

}

but a sealed class will allow you to do this and can hold a state thereby allowing multiple instances of the subtype to be created— You can pass any integer value to instantiate the February class in the below example.

sealed class Months {

class January(var shortHand: String) : Months()

class February(var number: Int) : Months()

}

What is this thing about “when”, “else” and “sealed classes”?

Since sealed classes cannot be extended and hence instantiated via subclass outside the file it is declared in, as the constructor is private.

However this is indirectly possible by subclassing subclasses of sealed classes.

Since sealed class restricts directly inheriting from it, the “when” construct (or the “switch” equivalent in Java) has only those restricted class instantiations to compare against and so the else case can be dropped provided you check it against all the declared types or else you need to use the else check with the when.

fun monthPrinter (month: Months){

when(month){

is Months.January -> {

println("Month is January")

}

is Months.February -> {

println("Month is February")

}



// This will throw a compile time exception if we don't add the

// else case as we have not added all subclasses of the sealed

// class to check it against }

}

The compile time error shown will be something like:

Error:(x, x) Kotlin: 'when' expression must be exhaustive, add necessary 'is Agility' branch or 'else' branch instead

Now that we have covered most if not everything related to sealed classes, let’s take a look at the actual definition provided in the official Kotlin site here.

“Sealed classes are used for representing restricted class hierarchies or in other words (private constructor with restricted inheritance and disallowing instantiations outside the declared file provides a restricted hierarchical structure), when a value can have one of the types from a limited set, but cannot have any other type. or in other words (using "when" (switch) in expression evaluation of the limited set of subtypes of the sealed class, we can exclude the else case as it cannot have any other type)”

Hope this helped in providing an entry point for further exploration of this wonderful feature of Kotlin.

Kotlin is not so bad when learnt through a Java lens right?

Please check out the references for more information on this.

That’s it from me. Happy coding folks.

References: