The beauty of Kotlin Type System

As Kotlin is a statically typed language fully compatible with Java, it has similar type system as Java does. Further more, Kotlin’s design choice introduces several enhancements, making it a more consistent, elegant, practical, and platform-agnostic language. Let’s explore some of these features to gain a better understanding of what makes Kotlin so appealing.
Any
Similar to Java’s Object
class which is every object’s root type, but there’re subtle difference between them. As the Java’s naming suggested, it’s only work for object types but not primitive types like int
, char
etc. Sure it involved to some low level memory management about where the variable should store, and we can gain more performance if using primative only. But Kotlin does a even better job here, it automatically transform to Java’s primitive type where possible and remove the need to declare primitive specifically from high level programing language perspective. The decision make it more consistant and also decouple it from the Java implementation to embrace Kotlin-multi-platform later.

public open class Any {
public open operator fun equals(other: Any?): Boolean
public open fun hashCode(): Int
public open fun toString(): String
}
When it come’s to Java specific implementation where Kotlin can’t get rid of, it sometimes leverage on Kotlin extension functions and put these extensions to seperate package, you can check how Java's
getClass()
function is implemented in Kotlin and also check how simple/elegant it is as theAny
definition in Kotlin above.
Optional
As NullPointerEexception(NPE) might be Java’s billion dollar mistake which I think every Java developer will encounter, Kotlin definitely don’t want to follow the same path.
The answer for this is also quite common nowadays — Nullability. Every type in Kotlin will have a nulltable version, and by declare the nullability specifically, we can have strong confidant where we have to or don’t have to do the null check and get rid of NPE forever thanks to Kotlin compiler.

There’s one subtle factor we used everyday but maybe not aware of. NonNull types and Nullable types are belong to different groups and only Nullable type can jump to NonNull type by proving its nullability no matter is via a null check or force-unwrap. So every NonNull/Nullable type stay in their own group consistantly hence promice the safety.
Though it’s safe to deal with null in Kotlin’s own world, you might want to know how about using Kotlin with Java togher. Check https://kotlinlang.org/docs/java-to-kotlin-nullability-guide.html for more information.
Nothing
Here comes the most interesting part of Kotlin type system from my own perspective — Nothing. Let’s first check the source code:
public class Nothing private constructor()
Even it just an one liner, it tells a lot.
- First, it’s not open so no one can extend it
- Second, the constructor is private and it don’t expose anything to instatiate itself.
- Lastly, there’s no any function it provided.
Seems a not useful type, right? Even if you’re unfamilia rabout Nothing, you can still write a bug free code without problem. However, if you delve into the documentation or comments for Nothing, you’ll soon discover it functions as a bottom type for every other type, the opposite of Any.

Why would we need a bottom type for anything? Wouldn’t it wired if it’s the child of a String and also an Int? Yes, the intersection of everything is something that couldn’t actually existed and that’s exactly the definition of Nothing
.
Let’s try the clasic example to elaborate more as the document said, a function has the return type of Nothing
, it means that it never returns (always throws an exception).
interface Animal {
fun eat(): String
fun walk(): String
}
class Dog : Animal {
override fun eat() = "dog eat"
override fun walk() = "dog walk"
}
Let’s define an Animal
type with two classic function and both return String
to display the action. What if we want to create a Fish
which extend from Animal
?
class Fish : Animal {
override fun eat() = "fish eat"
override fun walk() = throw RuntimeException("fish can't walk")
}
Because a fish can’t walk we would like to throw exception instead, and if you call walk
like below, you’ll see some interesting warning.
fun main() {
val fish = Fish()
fish.walk()
println("where am I") // IDE warn this will be unreachable code
}
And if you assign the type of fish to Animal
, the warning will disappear. If you check the return type of fish’s walk
function, you’ll found it automatically change to Nothing
from String
. Because Nothing
can’t existed, so a function with Nothing
as return type can’t return successfully, thus IDE can known the println
is unreachable. And because throw can happen anywhere, every type will have a child type as Nothing
. Hence IDE can do a better job and the language itself can have a better design which is more consistantly.
Nothing
is not limited to thow exceptions, a function with an infinite loop is also a valid case. The TODO()
will also return Nothing
as it shouldn’t successfully executed. And if you search the usage of Nothing
accross Kotlin itself, you might found it also used to represent any emtpy Collection as Nothing
can be the common child of everything. Although you can’t actually use it, but it serve as a good placeholder as you can swap later. Take listOf
for example:
var list: List<String> = listOf()
// Kotlin's Collections.kt
public inline fun <T> listOf(): List<T> = emptyList()
public fun <T> emptyList(): List<T> = EmptyList
internal object EmptyList : List<Nothing>
Bonus
Can you try to spot what is the extact type the myObj
inferred below? (Ans: can paste in IDE and try to reassign it)
var myObj = null
That’s it for today. With Any
as top type, Nothing
as bottom type and Optional
aside, I hope you’ll find Kotlin’s Type System so much enjoyable and beautiful.