• Lorenzo Quiroli

Nothing (Else) Matters in Kotlin

Everything has a type in Kotlin: objects, functions, nothing itself has a type, and it’s unsurprisingly Nothing.

There’s no void in Kotlin. Every function has a return type. Let’s start with an example:

fun doSomething() {
  Log.d("Hello", "World")

The above function returns Unit, as any other function that doesn’t explicitly declare a return type. Making the type explicit or implicit doesn’t really matter, thus the code above is exactly the same as:

fun doSomething() : Unit {
  Log.d("Hello", "World")

Since Unit is an actual return type, we can store a value of it, even if it’s not really useful:

val doSomethingResult = doSomething()

While Unit is often compared to the Java keyword void, it’s a different thing even if conceptually similar. Unit is a real class that inherits from Any with a single accepted value, which is a singleton (to avoid memory allocation every time a function returns Unit). And since it’s a normal object you can call toString() on it: the result is going to be “Kotlin.Unit”, which is hardcoded in the Unit object.

What about this function though:

fun fail() {
  throw RuntimeException("Something went wrong")

It’s the same as the other one, right? Its return type is still Unit. But does a function which is merely throwing an exception really have a return type? This function is returning nothing. Hey, maybe it should return Nothing:

fun fail() : Nothing {
  throw RuntimeException("Something went wrong")

Getting to know Nothing

Nothing is an uninhabited type, which means that no value can have this type at runtime, and it’s also a subtype of every other class.

But what’s the difference between Unit and Nothing as return type of a failing function? We can answer with just two lines of code:

val data: String = intent.getStringExtra("key") ?: fail()
textView.text = data

Let’s say that the method intent.getStringExtra("key") returns String?: these two lines behave differently depending on the return type of the fail() function. How?

  • If fail() returns Nothing, we won’t need to check for the nullability of the data value. We will either get a non null result or we will throw an exception.

  • If fail() returns Unit, you’ll get an error (type mismatch, required String found Unit), because you are basically trying to put a Unit inside a String.

What if you didn’t declare the type explicitly?

val data = intent.getStringExtra("key") ?: fail()
textView.text = data

  • If fail() returns Nothing, the inferred type will be String.

  • If fail() returns Unit, the inferred type will be Any (and you’d get an error, because the TextView requires a CharSequence.

Ok, I’m getting confused

It’s easy to understand the concept of Any in Kotlin because it’s basically the equivalent of Object, but there’s nothing like Nothing in Java (no pun intended). The closest thing is java.lang.Void, but, as we said before, there can be no valid instance of Nothing at runtime. You should be aware though that java.lang.Void::class is equivalent to kotlin.Nothing::class.

Since Nothing is a subtype of every other type, the compiler will be fine with it. But Nothing does way more than that: it guarantees that the second line won’t be executed if intent.getStringExtra returns null, and that allows us to just use the returning value of the function without the need of any additional checks. So you don’t have to add a null check before actually using the value:

val data: String? = intent.getStringExtra("key")
if (data == null) {
  throw IllegalStateException()
} else {

There’s no Nothing but there’s a null

Right now you might be wondering why you’d ever need to use Nothing in your code. The answer is that Nothing is just a compile time abstraction (since there are no instances of it). You should use it as the appropriate type when you want to explicitly mark a function that’s never going to complete successfully (because it’s going to throw an exception, enter a never-ending loop or result in a control flow transfer).

There is, though, one and only one instance of Nothing? and it’s called null. Yes, even null has got a type in Kotlin. Nothing? is the subtype of every nullable type in Kotlin. You should start to see the bigger picture here: nullable variables accept null because it’s a valid value from a subclass of their declared type.

As the Kotlin Language Specification states:

The null value is a special immutable atomic (structureless) value. Its exact type is Nothing? (it is the only value of this type), and it also belongs to every nullable type, usually indicating an absence of any valid value of the corresponding non-nullable type.

If you want to know more about Kotlin type hierarchy I’d suggest you read this great blog post.

Wrap up

Of course you could write perfectly working software with Kotlin without knowing of Nothing, but learning the language conventions helps other developers understanding your code better and makes it more expressive. If you had to see a function returning Nothing now, you’d understand without having to read it that it won’t complete normally, unlike a function returning Unit.

0 views0 comments