Contrast Unit with Nothing. When does a function return Unit versus Nothing, and how does each affect control flow?
answer
- Unit = 1 value, returns normally; Nothing = 0 values, never returns
- Nothing is the bottom type (subtype of all)
- Nothing-call => code after is unreachable
- ?: fail() works because Nothing fits anywhere
- error()/TODO()/throw return Nothing
basics
~10 sUnit means the function returns normally but with no useful value. Nothing means the function never returns at all -- it always throws or loops forever. Unit has one value; Nothing has none.
solid answer
~40 sUnit is the type of functions that **complete normally** but produce nothing meaningful; it has exactly one value. Nothing is the **bottom type** with **zero values**: a function declared to return Nothing can never return a value, so it must throw, loop forever, or call another Nothing function. Because Nothing is a subtype of every type, the compiler treats a `Nothing`-returning call as **unreachable afterward** -- code after `throw` or after a `fun fail(): Nothing = throw ...` is dead, and the expression can stand in for any type (e.g. `val x: Int = data ?: fail()`). A Unit call has no such effect; control flow continues normally. So the distinction is normal-completion-no-value (Unit) versus no-normal-completion (Nothing), which drives reachability analysis, smart casts after early returns, and exhaustiveness.
code
kotlin · 9 linesfun logUnit(msg: String): Unit = println(msg) // returns normally, no value
fun failNothing(msg: String): Nothing = // never returns
throw IllegalStateException(msg)
fun pick(id: Int?): Int {
val real = id ?: failNothing("id required") // Nothing fits where Int is needed
return real * 2 // reachable; real smart-cast to Int
}go deeper
Knows Unit = returns nothing useful, Nothing = always throws/never returns.
Explains the values count (1 vs 0) and that Nothing is the bottom type making ?: fail() type-check.
Uses Nothing's reachability/dead-code effects and smart-cast interaction confidently with stdlib helpers.
Positions both in the type lattice and explains how Nothing drives flow analysis, exhaustiveness, and API design (throw-helpers).
## Two opposite ideas - **Unit**: the function **finishes normally** but yields **no useful value**. One value (`object Unit`). Think 'done, nothing to report'. - **Nothing**: the function **never finishes normally** -- it always throws, loops forever, or delegates to another such function. **Zero** values. Think 'this never gives you anything back, ever'. ## Nothing is the bottom type `Nothing` is a **subtype of every type** (the bottom of the type lattice). That single fact powers a lot of Kotlin's flow analysis: ```kotlin fun fail(message: String): Nothing = throw IllegalStateException(message) val name: String = user.name ?: fail("missing name") // Nothing fits where String is expected ``` Because a `Nothing` expression can substitute for any type, `?: fail(...)` type-checks even though the left side is `String`. ## Control-flow / reachability effects The compiler knows a `Nothing`-returning call **does not return**, so: ```kotlin fun handle(x: Int?) { val v = x ?: return // 'return' has type Nothing println(v + 1) // v smart-cast to non-null Int; reachable fail("boom") println("dead") // unreachable; compiler warns } ``` `throw`, `return`, `continue`, `break`, and any `Nothing`-typed call all mark the following code unreachable. A **Unit** call does none of this -- execution simply continues. ## Summary table - Values: Unit = 1, Nothing = 0. - Subtyping: Unit is an ordinary type (subtype of Any); Nothing is a subtype of all types. - Returns normally? Unit yes; Nothing never. - Use: Unit for side-effecting functions; Nothing for throw-helpers (`error`, `TODO`, the failure path of `requireNotNull`) and unreachable branches. ## Keywords/APIs `Unit`, `Nothing`, `throw`, `return`, the stdlib helpers `error(...)`, `TODO()` -- all return `Nothing` on the failure path.
- Why does `val x: Int = y ?: throw ...` compile even though throw isn't an Int?throw has type Nothing, the bottom type, which is a subtype of Int, so it satisfies the expected type.
- Can you declare a variable of type Nothing?Not usefully -- there are no Nothing values, so the variable could never be assigned; it only appears as a return/expression type.
Unit is 'job done, nothing to report'; Nothing is 'this road has no exit' -- you never come back from it.
saying these in an interview costs you the question
- Saying both Unit and Nothing have one value
- Claiming a Nothing function returns Unit
- Not knowing Nothing is the bottom type
- Thinking code after throw stays reachable
- Confusing Nothing with null or with Unit