Much Ado About Nothing in Scala

Daniel Ciocîrlan

Daniel Ciocîrlan

4 min read  • 

scala type-syst...

Share on:

Introduction

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's type hierarchy showing Any at the top

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.

Enter Nothing

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.

Scala's type hierarchy showing Any at the top and Nothing at the bottom

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.

Nothing to Fear

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

Conclusion

I hope you’ve learned a bit about Nothing! Capitalization matters.