Why are null references called a billion-dollar mistake?
Because Tony Hoare, who introduced the null reference into ALGOL W in 1965, later described it exactly that way — apologising publicly for a design decision that has produced an enormous quantity of crashes and defects across every language that copied it.
His own account was that he added it simply because it was easy to implement, and that it has since caused innumerable errors, vulnerabilities and system crashes — costing, in his estimate, something on the order of a billion dollars.
Why it is genuinely a design flaw, not merely a source of ordinary bugs:
It makes every reference type secretly two types. A parameter declared as a string is actually "a string, or nothing at all". The type system claims one thing and permits another, so it lies.
The failure is deferred. Nothing catches the problem at the point where the null was introduced; it surfaces later, wherever the value is finally used, frequently far from the cause.
Nothing forces you to handle it. The compiler is content. You discover the omission at runtime, in production, from a user.
It conflates distinct meanings — not found, not applicable, not yet loaded, error, and genuinely empty are all represented identically.
How modern languages address it:
Option or Maybe types — Rust's Option<T>, Haskell's Maybe, Swift's optionals. Absence becomes a distinct type the compiler forces you to unwrap, so the omission is a compile error rather than a crash.
Non-nullable by default with explicit nullable types — Kotlin, Swift, TypeScript with strict null checks, and C# with nullable reference annotations. The default becomes safe; nullability is opt-in and visible in the signature.
Convenience syntax so the safe path is not tedious — optional chaining, null coalescing, if let bindings, and pattern matching.
The deeper lesson, which generalises well beyond null: make illegal states unrepresentable. If the type system cannot express the invalid case, no amount of care is required to avoid it.