Mastodon

It's Nothing

Nothing is a special type in Kotlin often used for errors. Is that all it's useful for though?

It's Nothing

Nothing is a special type in Kotlin to indicate that the execution of a function that returns it will not proceed. It does nothing. In practice, this is usually used as a means of indicating a given function (always) throws an exception and being able to declare it in the function's API signature directly. This is an advantage over Java, where you can only go as far as throwing an exception within a method but can't communicate that to its callers.

This post assumes you know all that already, and I'm not here to add the 134194th post on how Nothing works for errors.

Instead, I want to tell you about how it's not just for errors!

Here's the documentation on Nothing itself:

Nothing has no instances. You can use Nothing to represent "a value that never exists": for example, if a function has the return type of Nothing, it means that it never returns (always throws an exception).

You'll notice this is a little different than the way I phrased it above:

it will not proceed

Why? Because I think that's a slightly better mental model of how it actually works. Contrary to what the doc suggests, Nothing doesn't actually mean it "always throws an exception". In the context of a higher order function parameter on an inline function, it can also mean it returns. Remember - Nothing simply propagates that the function being called doesn't proceed. Much like throwing exceptions, it can be thought of as a form of GOTO. An early return can also be thought of this way (and as such, it should be used with care).

Here's a simple example:

inline fun example(body: () -> Nothing) {
  body()
}

fun main() {
  example {
    println("This works!")
    return
  }
}

Now, you might be thinking: what on earth is the point of that?

Fear not! Here's a real world application.

Swift has a language feature called guard. It's effectively shorthand for escaping out of a function if an optional variable is nil.

func example(_ input: String?) {
    guard let value = input else {
        show("input is nil!")
        return
    }
}
(yes yes swift guards also support where, but it's out of scope of this post)

You can also throw an exception here instead.

Escaping early... can be return or throw... sound familiar?

We can implement this in Kotlin with Nothing! No custom language support needed.

inline infix fun <T> T?.guard(block: () -> Nothing): T {
  return this ?: block()
}

fun example(input: String?) {
  val value = input guard {
    show("input is null!")
    return
  }
}

With a little help from infix, we get a pretty similar syntax and behavior.

What if example() returns something other than Unit? Simple - any return just has to return an instance of the return type.

fun example(input: String?): String {
  val value = input guard {
    return "input is null!"
  }
  
  return value
}

The best part is the compiler will enforce all of this for you. The IDE will properly highlight these too if you don't return or throw in the block.


So there you have it: it's kind of like GOTO.
Except it's not GOTO.
It's Nothing.

:)