← Wonderland

The Halting Problem

There are questions about computers that no computer can ever answer — and a single self-referential argument shows why.

There is a question you can ask about any computer program that sounds completely innocent. Given the program, and some input, will it eventually stop? Or will it run forever?

You would think this would be answerable. After all, computers are deterministic. The program is sitting right in front of you. The input is sitting right next to it. Surely some sufficiently clever piece of software could take both and decide.

In 1936, Alan Turing proved that no such software can ever exist. Not because we haven't been smart enough. Because the question, taken in full generality, is logically impossible to answer. This is the Halting Problem, and it remains one of the most surprising results in computer science.

A reasonable-sounding question

Start with what an answer would buy us. Imagine a tool — call it HALTS? — that takes any program P and any input x, and after some finite time tells you yes, P halts on x, or no, P loops forever on x. Just a function, returning a Boolean. Nothing exotic.

That tool would be miraculous. With it, your editor could warn you whenever you write an infinite loop. Mathematics would change: many famous conjectures — Goldbach's, the twin primes, the Collatz problem — can be encoded as the question of whether a particular search program ever halts. Feed them to HALTS? and we would know. So would any operating system; so would any contract verifier.

For some programs HALTS? is easy. A for-loop that runs ten times plainly halts. A while True: pass plainly doesn't. The question is whether there is one general algorithm that works for every program and every input. Turing showed there isn't.

program P input x HALTS? finite time, always answers yes — halts no — loops the decider we'd love to have

A hypothetical universal halt-detector. Turing's argument shows that no such machine can exist.

Turing's diagonal trick

Turing's argument is short and dazzling. It goes like this.

Suppose HALTS? exists. We don't have to know how it works inside. We just assume it is some program that, given P and x as inputs, finishes in finite time and answers correctly.

Now we build a new program out of it. Call it TROUBLE. It takes a single input — a program P — and behaves like this:

Ask HALTS? whether P, run on itself as input, would halt. If HALTS? answers yes, deliberately enter an infinite loop. If HALTS? answers no, halt immediately.

TROUBLE is just regular code. Nothing magical. It is allowed to exist if HALTS? is allowed to exist.

Now ask the fatal question: what happens when you feed TROUBLE itself as input to TROUBLE?

Run TROUBLE on TROUBLE ask HALTS?(TROUBLE, TROUBLE) answer: YES answer: NO so TROUBLE was supposed to halt… but by construction it now loops forever so TROUBLE was supposed to loop… but by construction it now halts immediately contradiction

Whichever way HALTS? answers, TROUBLE does the opposite. The only escape is to deny that HALTS? ever existed.

Either branch contradicts itself. The assumption that broke the world was that HALTS? exists in the first place. Therefore it does not.

The trick is essentially Cantor's diagonal argument re-dressed for computation. Cantor used it to show there are more real numbers than integers. Turing used the same self-referential structure to show there are more problems than there are programs that can solve them. Most of mathematics, in a precise sense, is not decidable by any machine.

What “undecidable” really means

It is important to be careful here. The Halting Problem is not saying that programs are mysterious — many specific programs are perfectly easy to analyse. It is not saying that compilers can't find bugs — many bugs are found. And it is not saying that artificial intelligence will eventually become smart enough to crack it. No amount of cleverness helps. It is not a difficulty problem; it is a logical impossibility.

For any halt-detector you build, there will always exist a program that fools it.

What it is saying: there is no single algorithm that works for every program. For any halt-detector you build, there will always exist a program that fools it. This sets a hard ceiling on what any tool, any verifier, any superintelligent system can ever do. It means program verification will always be partial. It means there can be no perfect antivirus that decides, for every executable, whether it will eventually misbehave. It means there are mathematical truths no formal system can ever prove — a result Kurt Gödel had reached by a different route five years earlier, and which Turing's argument made vivid and mechanical.

It also means something subtly cheering. Computation is not trivial. Turing's machines are powerful enough to encode questions whose answers their own kind cannot find. They contain genuine mystery. A purely mechanical universe can still be a deep one.

The shadow it casts

Once Turing opened this door, undecidability spread.

In 1953, Henry Rice showed that any non-trivial property of a program's eventual behaviour is undecidable. Not just “does it halt” but “does it ever print the number 5”, “does it ever exceed 1MB of memory”, “is it equivalent to this other program”. Rice's theorem is the Halting Problem dressed up in different clothes: if you could decide any of those, you could decide halting, and we already know you can't.

The same idea reached complexity theory in the 1970s. Some problems are decidable in principle but require absurd resources in practice; we still don't know whether P = NP, and undecidability hovers behind that question too. Static analysers, type checkers and model checkers — every modern tool that reasons about programs — explicitly carves out a sublanguage where decidability is recovered. Rust's borrow checker, for instance, deliberately rejects some perfectly safe programs, because deciding safety in full generality is impossible.

And then there is the philosophical aftershock. The Halting Problem is the first clean place where a mechanical system reasons about itself and discovers a question about itself it cannot answer. It is the same structure that surfaces in Gödel's incompleteness theorems, in Russell's paradox, in the liar's “this sentence is false”. Self-reference, taken seriously, always leaves something undecidable behind.

That is perhaps the deepest lesson. The world is not only stranger than we think; it is stranger than computation itself can ever decide.


Further reading

  1. Turing, A. (1936). On Computable Numbers, with an Application to the Entscheidungsproblem.
  2. Gödel, K. (1931). On Formally Undecidable Propositions of Principia Mathematica and Related Systems.
  3. Rice, H. (1953). Classes of Recursively Enumerable Sets and Their Decision Problems.
  4. Hofstadter, D. (1979). Gödel, Escher, Bach: An Eternal Golden Braid.
  5. Sipser, M. (1996). Introduction to the Theory of Computation, chapter 5.