Distinguish Unit, Unit?, Nothing, and Nothing? — what does each mean and how does each behave at the JVM/interop boundary?
answer
- Inhabitants: Unit=1, Unit?=2, Nothing=0, Nothing?=1
- null literal's type is Nothing?
- Unit return & Nothing return both ⇒ void
- Nothing? <: every nullable type
- Generic positions erase to Object
basics
~10 sUnit has one value; Unit? adds null. Nothing has no values and means 'never returns'; Nothing? has exactly one value, null. Each maps differently when crossing into Java.
solid answer
~40 s`Unit` is a single-value type (`Unit.INSTANCE`); as a function return it becomes JVM `void`. `Unit?` is `Unit` plus `null` — rarely used, it keeps the Unit value or null and so can't collapse to void in a value position. `Nothing` is the **bottom type** with **no** instances, meaning 'never returns normally'; in return position it lowers to `void`. `Nothing?` is the nullable bottom type whose **only** inhabitant is `null` — it is the type of the bare `null` literal and is assignable to any nullable type. At the boundary: `Unit`/`Nothing` returns ⇒ `void`; `Nothing?` ⇒ just `null` (no marker); generic uses erase to `Object`. The asymmetry: adding `?` to `Unit` (1 value) gives 2 values; adding `?` to `Nothing` (0 values) gives exactly 1 value (`null`).
code
kotlin · 5 linesval u: Unit = Unit // 1 value
val uq: Unit? = null // Unit or null
fun never(): Nothing = throw RuntimeException() // 0 values; void in bytecode
val nq: Nothing? = null // only inhabitant: null
val list = emptyList<Nothing>() // List<Nothing>: can never add an elementgo deeper
Knows Unit≈void and Nothing means never-returns; may not articulate the nullable variants.
Counts inhabitants correctly and knows null's type is Nothing?.
Explains subtyping (Nothing? <: T?), inference of List<Nothing>, and erasure/void at the JVM boundary.
Reasons about variance and least-upper-bound rules and how the type lattice (Nothing at bottom, Any? at top) shapes inference and interop erasure.
## The four types, by inhabitant count | Type | Instances | Meaning | |------|-----------|---------| | `Unit` | 1 (`Unit.INSTANCE`) | 'returns, but no useful value' (≈ void) | | `Unit?` | 2 (`Unit.INSTANCE`, `null`) | Unit-or-null; almost never meaningful | | `Nothing` | 0 | bottom type; 'never returns normally' | | `Nothing?` | 1 (`null`) | nullable bottom; the type of the `null` literal | ## `Unit` vs `Unit?` `Unit` is the ordinary 'no value' return. Adding `?` gives `Unit?`, which can hold the Unit singleton **or** `null`. Because it can be `null`, a `Unit?` **value** isn't void-collapsible the way a `Unit` return is — but it's almost never useful in practice. You may see it accidentally from an expression like a nullable `when` whose branches are statements. ## `Nothing` vs `Nothing?` `Nothing` (bottom, no instances) marks unreachable continuation. Adding `?` gives `Nothing?`, the **nullable** bottom type, whose **only** value is `null`. This is exactly why the bare literal `null` has type `Nothing?`: it's assignable to every nullable type (`String?`, `Int?`, …) because `Nothing? <: T?` for all `T`. ```kotlin val x: Nothing? = null // ok: only inhabitant is null val s: String? = null // null literal is Nothing?, assignable to String? fun loop(): Nothing { while (true) {} } // 0 inhabitants; compiles to void ``` ## JVM / interop behavior - `Unit` **return** ⇒ `void`. `Nothing` **return** ⇒ `void`. - `Nothing?` ⇒ no runtime marker; it's just a possibly-null reference (`null`). - In **generic positions** all of these erase: `List<Nothing>`, `List<Unit>` ⇒ `List` of `Object` at runtime; `Function0<Unit>` keeps `Unit` as the (erased) type argument needing `Unit.INSTANCE`. - Java sees none of the nullability or bottom-type subtleties — those are Kotlin-front-end concepts. Platform types and `@Nullable`/`@NotNull` annotations are the only nullability Java participates in, and they don't model `Nothing`. ## Why this matters Misreading these leads to puzzling inferred types: e.g. `emptyList()` may infer `List<Nothing>`, and `mutableListOf<Nothing>()` is useless because nothing can be added. Recognizing `Nothing?` as 'the type of null' demystifies many inference messages. ## Summary - Count inhabitants: Unit=1, Unit?=2, Nothing=0, Nothing?=1. - Unit/Nothing returns ⇒ void; Nothing? ⇒ plain null. - All are Kotlin-side; Java sees void/null/Object with no bottom-type semantics.
- Why is `emptyList()`'s default element type often `Nothing`?An empty list has no elements, so the most specific element type is the bottom type `Nothing`; `List<Nothing>` is a subtype of `List<T>` for any T (covariance), making the shared empty list reusable.
- Can you ever store a value in a `Nothing?` variable other than null?No — its only inhabitant is `null`, because the non-null part `Nothing` has zero instances.
Adding ? is adding one empty chair (null): a 1-seat room (Unit) becomes 2 seats; an empty room (Nothing) becomes a 1-seat room (Nothing?).
saying these in an interview costs you the question
- Saying Nothing? has no values (it has exactly one: null)
- Treating Unit? as commonly useful or collapsing it to void
- Not knowing the null literal's type is Nothing?
- Claiming Java can observe these nullability/bottom distinctions