# The Nothing
Type
A
Nothing
return type indicates a function that never returns
This is usually a function that always throws an exception.
Here’s a function that produces an infinite loop (avoid these)—because it never returns, its return type is Nothing
:
// NothingType/InfiniteLoop.kt
package nothingtype
fun infinite(): Nothing {
while (true) {}
}
Nothing
is a built-in Kotlin type with no instances.
A practical example is the built-in TODO()
, which has a return type of Nothing
and throws NotImplementedError
:
// NothingType/Todo.kt
package nothingtype
import atomictest.*
fun later(s: String): String = TODO("later()")
fun later2(s: String): Int = TODO()
fun main() {
capture {
later("Hello")
} eq "NotImplementedError: " +
"An operation is not implemented: later()"
capture {
later2("Hello!")
} eq "NotImplementedError: " +
"An operation is not implemented."
}
Both later()
and later2()
return non-Nothing
types even though TODO()
returns Nothing
. Nothing
is compatible with any type.
later()
and later2()
compile successfully. If you call either one, an exception reminds you to write implementations. TODO()
is a useful tool for “sketching” a code framework to verify that everything fits together before filling in the details.
In the following, fail()
always throws an Exception
so it returns Nothing
. Notice that a call to fail()
is more readable and compact than explicitly throwing an exception:
// NothingType/Fail.kt
package nothingtype
import atomictest.*
fun fail(i: Int): Nothing =
throw Exception("fail($i)")
fun main() {
capture {
fail(1)
} eq "Exception: fail(1)"
capture {
fail(2)
} eq "Exception: fail(2)"
}
fail()
allows you to easily change the error-handling strategy. For example, you can change the exception type or log an additional message before throwing an exception.
This throws a BadData
exception if the argument is not a String
:
// NothingType/CheckObject.kt
package nothingtype
import atomictest.*
class BadData(m: String) : Exception(m)
fun checkObject(obj: Any?): String =
if (obj is String)
obj
else
throw BadData("Needs String, got $obj")
fun test(checkObj: (obj: Any?) -> String) {
checkObj("abc") eq "abc"
capture {
checkObj(null)
} eq "BadData: Needs String, got null"
capture {
checkObj(123)
} eq "BadData: Needs String, got 123"
}
fun main() {
test(::checkObject)
}
checkObject()
’s return type is the return type of the if
expression. Kotlin treats a throw
as type Nothing
, and Nothing
can be assigned to any type. In checkObject()
, String
takes priority over Nothing
, so the type of the if
expression is String
.
We can rewrite checkObject()
using a [safe cast and an Elvis operator](javascript:void(0)). checkObject2()
casts obj
to a String
if it can be cast, otherwise it throws an exception:
// NothingType/CheckObject2.kt
package nothingtype
fun failWithBadData(obj: Any?): Nothing =
throw BadData("Needs String, got $obj")
fun checkObject2(obj: Any?): String =
(obj as? String) ?: failWithBadData(obj)
fun main() {
test(::checkObject2)
}
When given a plain null
with no additional type information, the compiler infers a nullable Nothing
:
// NothingType/ListOfNothing.kt
import atomictest.eq
fun main() {
val none: Nothing? = null
var nullableString: String? = null // [1]
nullableString = "abc"
nullableString = none // [2]
nullableString eq null
val nullableInt: Int? = none // [3]
nullableInt eq null
val listNone: List<Nothing?> = listOf(null)
val ints: List<Int?> = listOf(null) // [4]
ints eq listNone
}
You can assign both null
and none
to a var
or val
of a nullable type, such as nullableString
or nullableInt
. This is allowed because the type of both null
and none
is Nothing?
(nullable Nothing
). In the same way that an expression of the Nothing
type (for example, fail()
) can be interpreted as “any type,” an expression of the Nothing?
type, such as null
, can be interpreted as “any nullable type.” Assignments to different nullable types are shown in lines [1], [2] and [3].
listNone
is initialized with a List
containing only the null
value. The compiler infers this to be List<Nothing?>
. For this reason, you must explicitly specify the element type ([4]) that you want to store in the List
when you initialize it with only null
.
Exercises and solutions can be found at www.AtomicKotlin.com.