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 return
s. 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
.
You can also throw
an exception here instead.
Escaping early... can bereturn
orthrow
... 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.
:)