Daniel Ciocîrlan
4 min read •
Share on:
I’ve seen quite some confusion about the Nothing type in Scala and I wanted to shed some light on it. If you’re a Scala programmer, you might have seen Nothing once or twice, and you have at least the broad picture of Scala’s type hierarchy.
Scala is fully object-oriented, but the type hierarchy is not so standard. At the top of the hierarchy we have the Any type, which has two distinct type hierarchies below it. One starting with AnyVal, which contains all the value types (including Int, Boolean, etc), and then the AnyRef hierarchy which contains the reference types. Almost all the types we declare as programmers is a subtype of AnyRef, unless we explicitly extend AnyVal (rare and with little benefit). When we say
class MyPrecious
we are actually implying class MyPrecious extends AnyRef, which the compiler automatically infers. Even if you’ve not written Scala before, this hierarchy should be easy to understand. Things become trickier when we write things like:
def gimmeNumber(): Int = throw new NoSuchElementException
It’s the type of the throw expression that becomes the problem. Throw expressions don’t return an Int. I can also write
def gimmeString(): String = throw new NoSuchElementException
The throw expression doesn’t return a String either. It doesn’t return anything, it has no value. However, it’s an intuitive good replacement for both Int and String… and any other type you can conceive.
The throw expression returns Nothing, which is a type that does not and cannot have any instances. Not only that, but Nothing doesn’t have any values at all. Nothing is not Unit, not null, not anything. It’s the type of nothingness, if you will.
The most interesting aspect is that it benefits from special treatment by the compiler, because Nothing is a valid replacement for any type.
def gimmeNoNumber(): Int = throw new NoSuchElementException // Nothing
def gimmeNoString(): String = throw new NoSuchElementException // Nothing
def gimmeNoPerson(): Person = throw new NoSuchElementException // Nothing
Aside from crashing your program (which is a side effect), throw expressions return Nothing and they can be used as a replacement for any return type.
In a pretty ironic fashion, Nothing can replace anything, meaning that Nothing is a valid substitute for any type. In other words, Nothing is a valid subtype for all types. That’s why Nothing sits at the bottom of Scala’s type hierarchy.
Notice that in this picture, we also have the Null type which has the same purpose for reference types, and its only possible value is null - the same null you’ve been using all the time.
Having no possible values of type Nothing, can you actually use the Nothing type?
def aFunctionAboutNothing(x: Nothing): Int = 56
Sure you can. The above is a valid definition. The function takes a Nothing and returns an Int. However, you’d have a hard time calling it, since there are no values of Nothing to pass to it. You could call
aFunctionAboutNothing(throw new RuntimeException)
which compiles fine, but it will crash before your precious 56 would get returned.
Can you define functions returning Nothing?
def aFunctionReturningNothing(): Nothing = throw new RuntimeException
Sure. Nothing as a return type is used for expressions which never return normally, i.e. crash your JVM.
Can you use Nothing as a generic type argument?
case object Nil extends List[Nothing]
Yes, you can - in this case you’re typing List with Nothing, which means the Nil list can hold values of type Nothing… of which there aren’t any, so it’s an empty list. Nothing works great with generics and variance, but that is a subject for another post.
Finally, let me spend a few seconds on the stressful question marks:
def someMethodIHaventImplementedYet() = ???
The ??? is actually a method - Scala is really permissive with naming - whose implementation is simply this:
def ??? : Nothing = throw new NotImplementedError
I hope you’ve learned a bit about Nothing! Capitalization matters.
Share on: