What is the type of the literal `null`, and how do Nothing and Nothing? behave with generics like emptyList()?
answer
- `null` literal : Nothing?
- Nothing? has one value (null); Nothing has zero
- emptyList() = single List<Nothing> object
- Covariance + bottom => reusable empty collections
- Inferred Nothing/Nothing? => annotate the type
basics
~10 sThe bare null literal has type Nothing?, the nullable bottom type whose only value is null. Because Nothing is below everything, an empty list typed List<Nothing> can stand in for a list of anything.
solid answer
~40 s`null` by itself has type `Nothing?` — `Nothing` made nullable, inhabited only by `null`. Since `Nothing?` is a subtype of every nullable type `T?`, `null` is assignable to any nullable variable. For non-nullable bottom: `Nothing` is a subtype of all types, so a value that never exists fits anywhere. With covariant generics this is powerful: `emptyList<Nothing>()` (what `emptyList()` returns) is `List<Nothing>`, and because `List` is declared `out E`, `List<Nothing> <: List<T>` for any `T`. So one shared empty-list instance serves every element type. The compiler infers `Nothing` (or `Nothing?`) as a type argument when a generic value has no constraining info, e.g. `val xs = mutableListOf<Nothing?>()` after only adding nulls, which often signals you should specify the type explicitly to avoid an over-narrow `Nothing`-typed result.
code
kotlin · 6 linesval s: String? = null // null : Nothing? <: String?
val names: List<String> = emptyList() // List<Nothing> reused as List<String>
val ids: List<Int> = emptyList() // same EmptyList singleton
val inferred = listOf(null) // List<Nothing?> -- usually annotate insteadgo deeper
Knows null can go into any nullable variable but may not name Nothing? as its type.
States null : Nothing? and that Nothing? has only the null value.
Explains the emptyList()/List<Nothing> covariance trick and inference pitfalls clearly.
Reasons about why covariance makes the shared empty-collection sound while invariance forbids it for MutableList, and the soundness of bottom + variance.
## The type of `null` The literal `null` has type **`Nothing?`** — the nullable version of the bottom type. `Nothing?` is inhabited by exactly **one** value: `null`. Because `Nothing` is a subtype of every type `T`, `Nothing?` is a subtype of every nullable type `T?`. That is precisely why you can assign `null` to a `String?`, `Int?`, `List<User>?`, etc. ```kotlin val a: String? = null // Nothing? <: String? val b: Int? = null // Nothing? <: Int? ``` ## Nothing vs Nothing? - **`Nothing`** — zero values; used for never-returning code (`throw`, `TODO()`). - **`Nothing?`** — one value, `null`; used as the type of the bare `null` literal and for "only ever null" flow positions. ## Interaction with covariant generics Kotlin's `List<out E>` is **covariant**: `List<A> <: List<B>` when `A <: B`. Combine that with `Nothing` being the bottom: ```kotlin public fun <T> emptyList(): List<T> = EmptyList // EmptyList : List<Nothing> ``` `emptyList()` is backed by a single object `EmptyList : List<Nothing>`. Because `Nothing <: T` for every `T`, and `List` is covariant, `List<Nothing> <: List<T>` — so the **same** immutable empty-list instance is reusable as `List<String>`, `List<Int>`, anything. The same trick powers `emptySet()`, `emptyMap()`, and the singleton empty sequence. ```kotlin val names: List<String> = emptyList() // List<Nothing> seen as List<String> val ids: List<Int> = emptyList() // same EmptyList object ``` ## Inference pitfalls When the compiler has no information to pin a type parameter, it may infer `Nothing` or `Nothing?`: ```kotlin val xs = listOf(null) // List<Nothing?> xs.add("x") // (if mutable) would not compile: element type is Nothing? ``` Seeing `Nothing`/`Nothing?` in an inferred type is usually a hint to **annotate explicitly** (e.g. `mutableListOf<String?>()`), because a `MutableList<Nothing>` can hold nothing you can construct. ## Why invariant generics differ For an **invariant** type like `MutableList<E>`, `MutableList<Nothing>` is *not* a subtype of `MutableList<String>` — variance is the reason the empty-list trick works for read-only `List` but not for mutable collections. That is also why `emptyList()` returns a read-only `List`, never a `MutableList`.
- Why can the same emptyList() instance serve every element type, but emptyMutableList can't be shared the same way?List<out E> is covariant, so List<Nothing> <: List<T>. MutableList<E> is invariant (it both produces and consumes E), so MutableList<Nothing> is not a subtype of MutableList<T>; sharing a mutable one would be unsound.
- What is the difference in inhabitants between Nothing and Nothing??Nothing has zero inhabitants; Nothing? has exactly one, the value null.
A List<Nothing> is a vending machine guaranteed empty — safe to label as 'snacks', 'drinks', or anything, because it will never actually dispense a wrong item.
saying these in an interview costs you the question
- Saying null has type Any? or no type
- Claiming Nothing and Nothing? have the same number of values
- Asserting emptyList() returns a MutableList
- Not connecting the empty-list trick to out-variance
- Thinking MutableList<Nothing> is a subtype of MutableList<T>