[Kotlin Pearls 7] Unit, Nothing, Any (and null)

How to take advantage of Kotlin special Types

Uberto Barbini
ProAndroidDev
Published in
8 min readSep 6, 2019

It should be apparent, even to the casual reader of this blog, that I really like Kotlin as a language. One of the reasons is its Type Hierarchy, which is both very easy to work with and extremely powerful. It is also quite close to the Java Type System, so the interoperability is excellent.

To take full advantage of Kotlin Type Hierarchy is essential to understand how these three special types do work.

We will look in detail at Unit, Nothing, Any and compare their use against Java corresponding classes.

Finally, we also consider null and how types ending with ? fit into these categories.

Unit

The Unit type in Kotlin is the equivalent to the void type in Java.

Or, if you prefer, is the result value of any statement (for example println()).

fun whatIsLove(){
println("Baby don't hurt me!")
}

In Kotlin, we have two way to define a function or a method: as a statement, with the above syntax similar to Java or as an expression.

We can rewrite any statement without return type as an expression returning Unit:

fun whatIsLove(): Unit = println("Baby don't hurt me!")

Expressions are usually easier to read than statements, at least if we can keep them short. Long methods are not a good idea anyway.

In the Kotlin standard libraryUnit is simply defined as an object, implicitly inheriting from Any, with a single method override for toString().

public object Unit {
override fun
toString() = "kotlin.Unit"
}

Objects in Kotlin are classes with only one instance, which is created in the class static initializer.

For example:

object JustAnObject {    override fun toString(): String {
return "JustAnObject"
}
}

It is translated in ByteCode as a class JustAnObject with a static method INSTANCE to retrieve the singleton instance.

GETSTATIC com/ubertob/unitnothingany/JustAnObject.INSTANCE : Lcom/ubertob/unitnothingany/JustAnObject;public final static Lcom/ubertob/unitnothingany/JustAnObject; INSTANCE

When operating with Java code, Kotlin compiler is smart enough to translate any return void into Unit and the same for special function types.

For example, we can pass a java lambda of type Consumer<Integer> to a function expecting a parameter of type (Int) -> Unit .

//Java
public static Consumer<Integer> printNum = x -> System.out.println("Num " + x);
//Kotlin
fun
callMe(block: (Int) -> Unit): Unit = (1..100).forEach(block)
fun main(){
callMe { Lambdas.printNum } //it works fine
}

Note also that in Java there is a class called Void which, confusedly, it is only indirectly related to the keyword void and cannot be instantiated, so null is the only valid return value for a function with the result of type Void.

In case you are wondering, Void is needed to represent in Java reflection and Generics the concept of methods returning void, but differently from Unit is not the actual result values of those methods.

Nothing

Brace yourself here because this is the trickiest type here.

Nothing is a Class (not an Object) which is a subclass of any other class, including the final ones. There is a catch, though: it is impossible to instantiate a Nothing object because there is only a private constructor.

Its declaration is pretty simple:

public class Nothing private constructor()

Now you may wonder what is the point of having such a class if we cannot instantiate it. Actually, it is pretty useful, as we are going to show.

Since it’s not possible to pass a value of type Nothing, it represents the result of “a function that never returns.” For example, because it throws an exception or because it has an infinite loop.

In Mathematics and Functional Programming, Nothing is called the Bottom Type and represented with the symbol⊥.

In a computer program, any function, regardless of its return type, may not return a value, because of errors or infinite computations. Kotlin makes this property explicit with the Nothing type.

Let’s see some useful use cases, now.

The first is the TODO() function that you can use everywhere when you don’t want to specify an implementation yet.

public inline fun TODO(): Nothing = throw NotImplementedError()

Did you ever wonder how it can replace any possible expected return type? It works only because Nothing is a subtype of any class.

fun determineWinner(): Player = TODO() 
//It compiles because Nothing is a subclass of Player

Note that in Java you cannot write a similar function.

static Void todo(){
throw new
RuntimeException("Not Implemented");
}
String myMethod(){
return
todo(); //it doesnt' compile because Void is not a String
}

The second example is represented by all empty collections:

fun findAllPlayers(): List<Player> = emptyList()

How can the EmptyList of Kotlin standard library be a valid List<Player>? Look at the implementation solves the mystery:

public fun <T> emptyList(): List<T> = EmptyList 
//generic function using type inference
object EmptyList : List<Nothing> ... //ultimate covariancefun readUser(id: UserId): User? = …

As you probably guessed, it works because of Nothing type. Similarly, there are also emptyMap(), emptySet() etc.

The third example is maybe less typical of the previous two, but it is still quite useful.

Let’s say you have a function that can fail, for example, reading a user from database.

A simple and sensible choice can be returning a null when the user cannot be found. The signature can be like this:

fun readUser(id: UserId): User? = …

Sometimes we need more information about what exactly went wrong (connection can be down, table not exist ecc.) and let the called decide how to handle the failure.
Here Nothing cames to the rescue! A brilliant solution is to provide a callback in case of an error that returns Nothing.

inline fun readUser(id: UserId, onError: (DbError) -> Nothing): User = …

How does it work? Let’s see a full example:

fun createUserPage(id: UserId): HtmlPage {
val
user = readUser(id) { err ->
when (
err) {
is
InvalidStatement ->
return@createUserPage throw Exception(err.parseError)
is UserNotFound ->
return@createUserPage HtmlPage("No such user!")
}
}
return HtmlPage("User ${user.name}") //happy case
}

As you can see both throwing an Exception and a non-local return are a valid Nothing type.

To be able to call a non-local return from a lambda, you need to inline the calling function, readUser in this case.

A possible further evolution of this error handling pattern is wrapping the outcome on a functional Either with onError method. This will give us even more flexibility and composition possibilities at the cost of slightly higher code complexity. It is a matter for a future blog post anyway. Let me know if you would be interested.

It is simple to have a private constructor but how can Nothing be a subclass of anything else? How does it work “under the hood”?

It’s all compiler magic, in the ByteCode Nothing is translated as Void, while Unit is translated as void.

//Kotlin
fun neverReturn(): Nothing {
throw
Exception("never!")
}
//ByteCode
public final static neverReturn()Ljava/lang/Void;

Finally, it can be useful to remember the differences between Nothing and Unit:

fun fooOne(): Unit { while (true) {} }fun fooZero(): Nothing { while (true) {} }//both okfun barOne(): Unit { println("hi")}fun barZero(): Nothing { println("hi") }  //error//barZero not compiling

Note that Nothing is a subtype of Unit, that’s why the first compile but not the last one.

Any

Any in Kotlin is on the top of the hierarchy. All other types descend from Any.

From the class documentation: “The root of the Kotlin class hierarchy. Every Kotlin class has [Any] as a superclass.

It works like Java Object, but it has a much leaner signature:

public open class Any {
public open operator fun equals(other: Any?): Boolean
public open fun hashCode(): Int public open fun toString(): String
}

As a comparison java.lang.Object has 11 methods, of which five are about synchronization (wait, notify, notifyAll).

This is clearly an example of the advantages of coming later, it might seem a good idea at the time, but now having synchronization primitives on any possible object now seems unnecessary. There is also a reference on Valhalla project mailing list about it.

Looking at the code for Any, we can also see that is one of the few classes in the Kotlin stdlib that is open, meaning that is possible to inherit directly from it. This is necessary because every Kotlin class automatically inherits from Any, even if you don’t have to write it explicitly, you may do.

class MyClass: Any() {
fun
bye(): String = "bye bye"
}

Under the hood, at the JVM level, the Any type doesn’t exist and it gets compiled to java.lang.Object

For example:

fun whatIcanDoWithAny(obj: Any){
obj.toString()
}

Generate this bytecode where even if you are not familiar with the format. You can easily spot the actual type of the parameter (in bold).

public final static whatIcanDoWithAny(Ljava/lang/Object;)V
// annotable parameter count: 1 (visible)
// annotable parameter count: 1 (invisible)
@Lorg/jetbrains/annotations/NotNull;() // invisible, parameter 0
L0
ALOAD 0
LDC "obj"
INVOKESTATIC kotlin/jvm/internal/Intrinsics.checkParameterIsNotNull (Ljava/lang/Object;Ljava/lang/String;)V
L1
LINENUMBER 5 L1
ALOAD 0
INVOKEVIRTUAL java/lang/Object.toString ()Ljava/lang/String;
POP

Even if they are not easily accessible from Kotlin, all Kotlin objects do have all the methods missing in Any, like notify, wait, etc.

This also makes possible to pass any Kotlin object to a Java method which is expecting an Object.

Finally, note that the Any class implements the equals operator, which is mapped on the Java equals method of Object class. As a consequence, equals == is the only operator in Kotlin that needs to be overridden and you cannot change its signature, for example, to return some kind of Difference class instead of a Boolean.

null

The last protagonist of this post is not a type but it unique because it has no type. If you want, you can consider null the opposite of Nothing: a value without a Type, while Nothing is a Type that cannot be instantiated.

In Kotlin, null can form special union types with any other type, making them “nullable” and denoting them with the question mark.

So String? is the union of the type String plus the null.

In this way, Kotlin with the help of smart casts and special operators make easy to handle null safely.

What about our special types?

Unit? allows you to return a statement or null. I don’t know of any interesting use of it.

Nothing? Is particular because it is the only way to force a function to have null as the only possible result. Still no practical use as far as I know.

Any? is important because it is the equivalent of Java Object, since in Java you can return null.
Also when declaring a generic class MyClass<T> the implicit bound of T is Any?, like in Java. If you want to restrict your generic class to non-nullable types, you have to state it explicitly: MyClass<T: Any>

Another way to look at null is syntax sugar for the Optional/Maybe type, that can represent a value or the lack of.

Just an exercise let’s rewrite map and flatmap as extension functions for any nullable in Kotlin.

fun <A:Any, B:Any> A?.map(f: (A) -> B): B? = when(this) {
null
-> null
else
-> f(this)
}
fun <A:Any, B:Any> A?.flatMap(f: (A) -> B?): B? = when(this) {
null
-> null
else
-> f(this)
}

The full code for these examples and more is on my GitHub project.

I hope you liked this post, if so please applaud it and follow me on Twitter and Medium.

The feedback so far on this series of posts has been very positive, thanks to everybody commended and shared my posts.

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

Published in ProAndroidDev

The latest posts from Android Professionals and Google Developer Experts.

Written by Uberto Barbini

JVM and Kotlin independent consultant. Passionate about Code Quality and Functional Programming. Author, public speaker and OpenSource contributor.

Responses (4)

What are your thoughts?