skip to content

Why is Nothing a subtype of every type, and what does that enable in everyday Kotlin code?

level: middleimportance: must knowfreq 60%

answer

  1. Bottom type = subtype of all types
  2. Vacuously safe: no values to break contracts
  3. Rescues elvis: `?: throw / return / error`
  4. LUB(T, Nothing) = T in branch unification
  5. emptyList() is List<Nothing>

basics

~20 s

Nothing sits at the bottom of Kotlin's type hierarchy, so it counts as every type at once. That lets a throw or a never-returning call be used wherever any value is expected, like on the right of the elvis operator.

solid answer

~40 s

Nothing is the bottom type: by definition it is assignable to a variable of any type T, because there are no Nothing values that could violate T's contract. This subtyping makes never-returning expressions usable in value positions. The classic case is the elvis operator: `val name = user.name ?: throw IllegalArgumentException()` — `throw` has type Nothing, which is a subtype of String, so the whole expression types as String. Same with `?: return`, `?: TODO()`, `?: error(...)`. It also makes `if`/`when` branch unification work: if one branch throws, the result type is determined entirely by the other branch, since Nothing widens to whatever the other branch produces. The least upper bound of `T` and `Nothing` is always `T`.

code

kotlin · 4 lines
kotlin
fun fail(msg: String): Nothing = throw IllegalStateException(msg)

fun port(config: Map<String, String>): Int =
    config["port"]?.toIntOrNull() ?: fail("port missing or invalid")

go deeper

for a junior

Recognizes that throw/return can appear after ?: but may not explain why.

for a middle

Explains bottom-type subtyping and gives the elvis and when-branch examples correctly.

for a senior

Articulates least-upper-bound branch unification and ties null's type to Nothing?.

for a principal

Connects Nothing to variance (List<Nothing>/emptyList) and explains the vacuous-soundness argument for bottom-type subtyping.

## Bottom type = subtype of all types In a type lattice, the **bottom type** is a subtype of every other type. Kotlin's bottom type is `Nothing`. The reasoning is vacuous-truth: a value of type `Nothing` would have to satisfy the contract of *every* type, but since **no such value exists**, there is nothing to check — so the subtyping holds trivially and safely. ### Why this is sound Subtyping says "an `S` value can be used where a `T` is expected." If `S = Nothing` has no values, no actual substitution ever happens at runtime, so it can never break `T`'s guarantees. ### What it enables **1. Elvis with throw/return/error — value position rescue.** ```kotlin fun greet(user: User): String = user.name ?: throw IllegalArgumentException("no name") // 'throw ...' : Nothing -> Nothing <: String -> expression : String ``` The right-hand side of `?:` must be a subtype of the left's non-null type. `Nothing` always qualifies. **2. Branch unification in `if`/`when`.** ```kotlin val level: Int = when (status) { "ok" -> 0 "warn" -> 1 else -> error("unknown: $status") // Nothing } ``` The common supertype (least upper bound) of `Int` and `Nothing` is `Int`. Branches that don't return effectively "drop out" of the result type. **3. Helper functions that never return.** ```kotlin fun fail(msg: String): Nothing = throw IllegalStateException(msg) val port = config["port"]?.toInt() ?: fail("port missing") ``` `fail` is reusable in any value slot because its `Nothing` return is a subtype of `Int` here. ### Relationship to Nothing? `Nothing?` is `Nothing` made nullable: its only value is `null`. So the literal `null` has type `Nothing?`, which is a subtype of every nullable type `T?` — that is why `null` can be assigned to any nullable variable. ### Generic / variance angle Because `Nothing` is the bottom, an empty list can be typed `List<Nothing>` and, with `out` variance, be used as `List<String>`, `List<Int>`, etc. `emptyList()` returns `List<Nothing>` under the hood for exactly this reason.

  • What is the least upper bound of String and Nothing?
    String. Nothing is a subtype of String, so their common supertype is String — branches that throw don't widen the result type.
  • How does this relate to emptyList()'s type?
    emptyList() returns List<Nothing>. Because List is declared `out` (covariant) and Nothing is the bottom, List<Nothing> is a subtype of List<T> for any T, so an empty list works everywhere.

Nothing is a universal blank key: it fits every lock precisely because it never actually turns one.

saying these in an interview costs you the question

  • Saying Nothing is a subtype only of nullable types
  • Claiming throw works in elvis because of special compiler magic, not subtyping
  • Confusing Nothing (bottom) with Any (top)
  • Thinking branch unification picks Nothing as the result type
  • Not knowing null's type is Nothing?

context