skip to content

Junior-friendly but commonly confused: distinguish Unit, Nothing, and Any in Kotlin's type model, and where each one shows up.

level: juniorimportance: should knowfreq 60%

answer

  1. Count values: Any=many, Unit=one, Nothing=zero
  2. Unit = void but is a real value/type
  3. Nothing = never returns (throw/TODO/error)
  4. Any = top type, parent of all non-null
  5. Unit composes with generics; void does not

basics

~20 s

Any is the parent of all types. Unit is the type for functions that return nothing useful (like void) and has exactly one value. Nothing means a function never returns at all, such as one that always throws.

solid answer

~40 s

These three sit at meaningful spots in the lattice. **Any** is the top type — supertype of every non-null type, exposing only equals/hashCode/toString. **Unit** is Kotlin's stand-in for 'no meaningful result': it is a real type with exactly **one** value, the `Unit` object, returned implicitly by functions with no declared return type (like `void`, but a value, so it composes with generics). **Nothing** is the bottom type with **zero** values; a function returning `Nothing` never returns normally (it throws, loops forever, or exits). The count of values is the crisp distinguisher: Any has many, Unit has one, Nothing has none. You see Unit as the default return type and as `() -> Unit` lambdas; you see Nothing in `throw`, `TODO()`, and `error()`; you see Any in heterogeneous collections and generic bounds.

go deeper

for a junior

Separates Unit (no useful return) from Nothing (never returns) and Any (parent of all).

for a middle

Explains Unit is a single-value type that composes with generics unlike void, and that Nothing has zero values.

for a senior

Connects Nothing being a subtype of everything to Elvis-throw, TODO/error stubbing, and unreachable-code analysis.

for a principal

Uses the value-count framing to reason about API signatures, sealed exhaustiveness, and how these endpoints anchor the type lattice.

## Three types people mix up ### `Any` — the top type `Any` is the supertype of every non-nullable type (its nullable form `Any?` tops the whole lattice). It only declares `equals()`, `hashCode()`, and `toString()`. You use it when a value can be 'anything': ```kotlin val mixed: List<Any> = listOf(1, "two", 3.0) ``` ### `Unit` — 'no useful value', but still a value `Unit` is a real type with **exactly one** instance, the singleton object `Unit`. A function that declares no return type returns `Unit` implicitly: ```kotlin fun log(msg: String) { println(msg) } // returns Unit fun log2(msg: String): Unit { println(msg) } // identical ``` Unlike Java's `void` (which is not a type and has no value), `Unit` *is* a type, so it composes with generics and function types: `() -> Unit`, `List<Unit>`, etc. That is why a lambda body's last statement can 'return Unit'. ### `Nothing` — never returns `Nothing` has **no** values. A function typed `Nothing` cannot return normally — it throws, loops forever, or terminates the process. Standard helpers `TODO()`, `error(...)`, and the `throw` expression all have type `Nothing`. ```kotlin fun notReady(): Nothing = TODO("implement me") val x: Int = config ?: error("missing") // error() : Nothing fits Int ``` Because `Nothing` is a subtype of every type, it slots into any branch and lets the compiler keep the surrounding type non-null and mark following code unreachable. ## The crisp mnemonic: count the values | Type | Number of values | Meaning | |------|------------------|---------| | `Any` | many | top type, parent of all | | `Unit` | exactly one | 'done, nothing useful to return' | | `Nothing` | zero | 'never returns / unreachable' | ## Where you meet them - `Any`: heterogeneous collections, the default upper bound of an unbounded generic (`<T>` means `<T : Any?>`). - `Unit`: default return type; callback/lambda types `() -> Unit`. - `Nothing`: `throw`, `TODO()`, `error()`, infinite loops, Elvis-throw idioms.

  • Why does Kotlin use Unit instead of Java's void?
    Unit is an actual type with a value, so it works uniformly with generics and function types (e.g. () -> Unit, a List<T> where T = Unit); void is not a type and cannot.
  • What is the return type of TODO() and why is that useful?
    Nothing. Because Nothing is a subtype of everything, TODO() type-checks in any context, letting you stub a function of any return type without compile errors.

Unit is a delivery receipt (one fixed slip saying 'done'); Nothing is a package that never arrives; Any is the warehouse that can hold any package.

saying these in an interview costs you the question

  • Saying Unit and Nothing are the same
  • Calling Unit 'void' with no value
  • Thinking Nothing has one value like Unit
  • Believing a function can return a real Nothing value
  • Confusing Any with Any? regarding null

context