skip to content

What is the type of the null literal in Kotlin, and how does Nothing? relate to nullable types?

level: seniorimportance: should knowfreq 38%

answer

  1. null : Nothing?
  2. Nothing = bottom type, empty value set, subtype of all
  3. Nothing? value set = {null}
  4. Nothing? <: every T?, so null fits anywhere nullable
  5. throw / TODO() return Nothing

basics

~10 s

The null literal has type Nothing?. Nothing has no values at all, so Nothing? has exactly one value: null. That's why null can be assigned to any nullable type.

solid answer

~50 s

In Kotlin the literal null has the type Nothing?. Nothing is the bottom type — it has an empty value set and is a subtype of every type. Adding ? gives Nothing? a value set of exactly {null}, since Nothing contributes nothing. Because Nothing is a subtype of every T, Nothing? is a subtype of every T?, which is precisely why the single value null is assignable to String?, Int?, User? and any other nullable type. When you write val x: String? = null, the literal's Nothing? type is widened to String?. This also explains type inference: val x = null infers Nothing?, which is rarely useful, so you usually annotate. Nothing also appears as the return type of functions that never return normally (throw, infinite loops), letting expressions like val s = name ?: throw ... type-check, because Nothing is a subtype of String.

code

kotlin · 6 lines
kotlin
val inferred = null        // type is Nothing?
val s: String? = null      // Nothing? widened to String?

fun nonEmpty(x: String?): String =
    x?.takeIf { it.isNotBlank() }
        ?: throw IllegalStateException("blank")  // throw : Nothing <: String

go deeper

for a junior

Knows null can be assigned to nullable types but may not name its type.

for a middle

States null : Nothing? and that null fits any nullable, with rough reasoning.

for a senior

Explains Nothing as the bottom type, derives Nothing? <: T?, and the inference pitfall of val x = null.

for a principal

Places Nothing/Nothing?/Any? in the full type lattice and uses Nothing in control-flow typing (throw/TODO) to reason about soundness.

## Nothing: the bottom type `Nothing` is Kotlin's **bottom type**: it has **no instances** (an empty value set) and is a **subtype of every other type**. You can never create a `Nothing` value; it represents 'this computation does not produce a value' — e.g. a function that always throws or loops forever has return type `Nothing`. ## The type of `null` The literal `null` has type **`Nothing?`**. Break it down: - `Nothing` contributes **zero** values. - The `?` adds `null`. - So `Nothing?`'s value set is exactly **`{null}`** — the single value `null`. ```kotlin val x = null // inferred type: Nothing? ``` ## Why null fits every nullable type The subtyping propagates the nullable suffix: - `Nothing <: T` for every `T` (bottom type rule). - Therefore `Nothing? <: T?` for every `T`. Since `null : Nothing?` and `Nothing? <: String?`, the value `null` is assignable to `String?`, `Int?`, `List<User>?`, etc. The compiler widens `Nothing?` to the target nullable type: ```kotlin val a: String? = null // Nothing? widened to String? val b: Int? = null // Nothing? widened to Int? ``` There is no `null` value 'belonging' to each type separately — there's one `null`, typed `Nothing?`, that flows into any nullable slot. ## Inference pitfall Because `val x = null` infers `Nothing?`, you can't later store a real value in it: ```kotlin var x = null // Nothing? // x = "hi" // ERROR: String is not Nothing? var y: String? = null // annotate to get a useful type ``` ## Nothing (non-null) in control flow `Nothing` (without `?`) powers expressions that never return. `throw` is an expression of type `Nothing`, and since `Nothing <: String`, this type-checks: ```kotlin fun req(name: String?): String = name ?: throw IllegalArgumentException("missing") // the throw branch has type Nothing, a subtype of String ``` `TODO()` and `error()` likewise return `Nothing`, letting them satisfy any expected type. ## Summary of the lattice - Top of the hierarchy: `Any?` (every value + null). - Bottom: `Nothing` (no values), subtype of all. - `null`'s type: `Nothing?`, subtype of every `T?`, holding the lone value `null`.

  • Why does val x = null produce a nearly useless variable?
    It infers type Nothing?, whose only value is null, so you can never assign a non-null value to it. You must annotate (e.g. String?) to get a usable nullable variable.
  • How does Nothing make name ?: throw ... type-check as a String?
    throw is an expression of type Nothing, and Nothing is a subtype of String, so both branches of the Elvis conform to the expected String result type.

Nothing is an empty bag; zipping a ? onto it gives a bag whose only content is the 'absence' token null.

saying these in an interview costs you the question

  • Saying null has type 'Null' or 'Any?' instead of Nothing?
  • Confusing Nothing (bottom, no values) with Unit (one value)
  • Thinking each nullable type has its own distinct null value
  • Not knowing Nothing is a subtype of every type

context