Skip to content

To Halt or Not to Halt?

Cover image for To Halt or Not to Halt?

Can you tell if a program will run forever or not?

Some programs are obvious:

x = 5
print(x)
# Halts. Obviously.
while True:
    print("send help")
# Does not halt. Because the condition is always true.

But then there’s this:

def collatz(n):
    while n != 1:
        if n % 2 == 0:
            n = n // 2
        else:
            n = 3 * n + 1
    return n

collatz(27)

Does it halt? It seems to halt for every number ever tested (up to 2⁷⁰). But no one has proven it always does. This is the Collatz conjecture, unsolved for 80+ years.

Now imagine you want a program — call it HaltChecker — that can analyze any program and tell you if it halts. Too bad it can’t exist.

Proof by contradiction

Assume HaltChecker(program, input) exists. It returns True if the program halts, False if it loops forever.

Now let’s be devious:

def paradox(program):
    if HaltChecker(program, program):
        # It says we halt? Cool, let's loop forever.
        while True:
            pass  # spite
    else:
        # It says we loop forever? Let's halt immediately.
        return  # gotcha

What happens when we run paradox(paradox)?

Case 1: HaltChecker says paradox(paradox) halts. → So paradox enters the infinite loop. It doesn’t halt. → HaltChecker was wrong. Contradiction.

Case 2: HaltChecker says paradox(paradox) loops forever. → So paradox returns immediately. It halts. → HaltChecker was wrong. Contradiction.

Both cases contradict. Therefore, HaltChecker cannot exist. QED.

The program literally asks, “What will I do?” and then does the opposite. It’s a self-referential paradox.

Why Should You Care?

The implications of this are:

  • No perfect bug detector — Many bugs reduce to the halting problem. “Does this code ever access memory it shouldn’t?” is equivalent to asking if certain code paths halt.

  • No perfect virus scanner — Determining if a program is malicious often means figuring out what it does. Which can require solving halting.

  • No perfect optimizer — Many optimizations require knowing if code paths are reachable. Which can reduce to halting.

  • Rice’s Theorem makes it worse — Any non-trivial property of program behavior is undecidable. The only decidable properties are the ones that are true for all programs or none.

But My IDE Catches Bugs?

Yes, but with caveats. Your IDE can:

  • Check syntax (decidable)
  • Check types (mostly decidable)
  • Flag some bugs (conservative guesses)

Your IDE cannot:

  • Guarantee no infinite loops
  • Guarantee no bugs
  • Prove your program is correct

It uses approximations.

Approximations

  • Time limits — “Can’t prove it halts, but I’ll kill it after 10 seconds.” Operating systems do this constantly.

  • Restricted languages — Some languages (Coq, Agda) don’t allow general recursion — all functions must provably terminate. You lose expressiveness, but you gain guarantees.

  • Heuristics — We can catch obvious infinite loops:

while True:  # yeah, this isn't stopping
    pass

We can use loop bound analysis, termination checkers, static analysis.

The Philosophical Bit

The halting problem says: there are true statements about programs that no algorithm can prove.

This connects to Gödel’s Incompleteness Theorems (1931): any sufficiently powerful mathematical system contains true statements that cannot be proven within that system.

Turing showed computation has the same ceiling. Some questions are perfectly well-defined but algorithmically unanswerable.

Questions this raises:

  • Can humans solve problems computers can’t? (Debatable)
  • Does the brain have computational limits? (Probably)
  • Are some truths fundamentally unknowable? (Perhaps)

The Hierarchy of Impossible

Just when you thought it couldn’t get worse: the halting problem is only level one of an infinite hierarchy.

  • Level 0: Decidable.
  • Level 1: The halting problem. Undecidable.
  • Level 2: “Does a program with a halting oracle halt?” Still undecidable.
  • Level 3: “Does a program with a level-2 oracle halt?” And so on.

This is the Arithmetic Hierarchy. It goes forever. Each level is strictly harder than the last.

The universe of computation is full of increasingly impossible questions. The halting problem is just the door.