Computability Basics

The Halting Problem in Plain Language

Why no general program can decide whether every program eventually stops, explained with a step-by-step contradiction and practical consequences.

On this page
  1. The question
  2. Why a tool seems possible
  3. The argument, in steps
  4. What kind of impossibility this is
  5. Semi-decidability
  6. Consequences you can feel
  7. A grid-language flavor
  8. Key points to remember

The question

Imagine you want a tool that takes any program and its input, and tells you in finite time whether that program will eventually finish or run forever. It would be wonderfully useful: no more infinite loops, no more waiting to see whether a long computation will ever end. The halting problem asks whether such a tool can exist. The answer, proved by Alan Turing in 1936, is no.

The precise claim is narrow and worth stating carefully. There is no single program that, for every possible program and input, always gives a correct yes or no answer about halting. It does not say that you can never tell whether a particular program halts. Many programs are easy to judge.

Why a tool seems possible

For specific programs, analysis often works. A loop that counts from one to ten obviously ends. A loop that never changes its condition obviously does not. So it is tempting to think a smart enough program could handle all of them. The difficulty is that programs can do arbitrarily clever things, including looking at other programs.

The argument, in steps

The proof is by contradiction. Suppose, for the sake of argument, that a perfect halting checker exists. Call it H. Given a program P and an input I, H always finishes and answers “halts” or “runs forever,” correctly.

Now build a new program, call it Trouble, that takes a program text as its input and does the following:

  1. Run H to ask what happens when the given program is run on its own text as input.
  2. If H answers “halts,” make Trouble enter an infinite loop.
  3. If H answers “runs forever,” make Trouble stop immediately.

In other words, Trouble does the opposite of whatever H predicts.

Now ask the awkward question: what happens when we run Trouble on its own text?

  • If H says Trouble halts on its own text, then Trouble loops forever. H was wrong.
  • If H says Trouble runs forever on its own text, then Trouble stops. H was wrong again.

Either way, H gave a wrong answer on this one case. That contradicts the assumption that H is always correct. The only thing we assumed was that H exists, so H cannot exist.

The structure resembles the old puzzle of the sentence “this statement is false.” The program is built so that it asks about itself and then contradicts the answer. Nothing in the argument depends on computer speed, memory size or clever design, which is why it is considered a fundamental limit.

What kind of impossibility this is

The result is not about missing technology. It applies to any model of computation that is at least as powerful as a Turing machine, so it covers every language with unbounded memory and loops. By the Church-Turing thesis, the statement is also believed to hold for any mechanical procedure at all.

It is also a statement about universality. A system must be able to simulate programs, including ones that look at themselves, for the argument to apply. This is why the halting problem is tied to Turing completeness: a language that is universal enough to be interesting is also powerful enough to run into undecidability. Weaker systems, such as finite automata, can have a decidable halting question precisely because they cannot count or simulate arbitrarily.

Semi-decidability

There is one half of the problem that can be handled. To find out whether a program halts, you can simply run it. If it halts, you will eventually see that. The trouble is the other case: if it is still running, you cannot tell whether it is about to stop or will go on forever. This lopsidedness is called semi-decidability. A halting detector exists for the yes side, but not a reliable one for the no side.

Consequences you can feel

The halting problem is the root of many other impossibility results. If you could solve some other question perfectly, you could use that solution to solve halting, which is impossible, so the other question is impossible too. Examples include deciding whether two programs always behave the same way, or whether a program will ever print a certain character. Many undecidable properties of programs are shown this way.

It also explains why practical tools behave as they do:

  • Compilers and linters warn about suspicious loops, but they cannot always be right. They approximate, sometimes flagging safe code or missing real problems.
  • Test harnesses use timeouts. A timeout does not decide halting; it just gives up after a limit.
  • Static analyzers may refuse to answer for hard cases, or accept some false alarms.

None of this means analysis is useless. It means no analyzer can be both perfectly accurate and fully general.

A grid-language flavor

In a language such as the Befunge language, you can see the principle in miniature. A program might send the instruction pointer around a loop whose exit depends on a calculation. Whether the exit is ever reached can be as hard to determine as an arbitrary program’s behavior. For a small hand-written program you can usually do tracing by hand and find out, but a general detector that works on all grid programs would let you solve the halting problem, and so it cannot exist.

Key points to remember

  • The halting problem is unsolvable in general, not unsolvable in every case.
  • The proof uses a program that contradicts the prediction made about it.
  • Running a program confirms halting but cannot confirm non-halting.
  • Many practical questions inherit the same difficulty.

The complete guide to computability basics

Computability Ideas for Curious Programmers
Read the guide

Keep exploring

Guides from other topics

All topics →