Visual walkthrough — Halting problem — undecidability proof by diagonalization
This page is the visual companion to the parent proof. Prerequisite ideas — Turing Machines, Decidable vs Recognizable Languages, Cantor's Diagonal Argument — are re-explained in pictures as they arise, so you can read straight through.
Step 1 — A program is just a string
WHAT. Before any logic, one plain fact: the source code of a program is a finite sequence of characters. That means a program can be stored, copied, and — crucially — handed to another program as ordinary input data.
WHY. The whole proof rests on feeding a program its own code. If code weren't just data, "run on " would be nonsense. So we must earn this idea first. (This is the same insight that makes the Universal Turing Machine possible — one machine reading another machine's description.)
PICTURE. On the left, a little program P drawn as a scroll of text. An arrow carries that same scroll into an input slot on the right. The program and the data are the identical object — only the role differs.

Every one of these symbols is now defined. We will not use a new one before naming it.
Step 2 — Suppose the perfect predictor exists
WHAT. Assume — for the sake of argument — that somebody hands us a total program called . "Total" means: always halts and always answers correctly. Its job:
Reading the equation term by term: takes two arguments — the first is the program we are curious about, the second is the input that program would receive. It returns one of exactly two labels, or .
WHY. We want to prove cannot exist. The cleanest weapon against "X exists" is proof by contradiction: pretend it does, then derive an absurdity. The absurdity we manufacture will force the pretence to collapse.
PICTURE. A black box labelled with two input wires (P and w) and one output wire that lights up either green or red . A tick mark reminds us: it always answers — never gets stuck.

Step 3 — The table of all behaviours (the grid we will attack)
WHAT. List every program down the rows: (there are infinitely many, but they can be numbered — that is what "listable" means). Across the columns, list the same programs used now as inputs. Cell records the answer to "does halt on ?" — an H or an L.
WHY. , if it exists, fills in this entire grid correctly. To break we only need to break one column against one row — the diagonal. Laying out the grid makes the target visible. (This is exactly the stage on which Cantor's Diagonal Argument plays out: a grid, and a diagonal you deliberately disagree with.)
PICTURE. A grid. The diagonal cells — "does halt on itself?" — are highlighted in orange. Those diagonal answers are the only ones we will touch.

Step 4 — Build the troublemaker
WHAT. Using as a helper, define a new program that takes one program as input:
D(P):
if H(P, P) == HALT: # ask: does P halt on its own code?
loop forever # then D deliberately loops
else: # H said P loops on itself
halt # then D deliberately halts
Term by term: calls — the diagonal question for . Then does the opposite of that prediction. Predicted HALT loops. Predicted LOOP halts.
WHY. is a machine for disagreeing with the diagonal. In grid language: if the diagonal cell says H, produces L there; if it says L, produces H. 's row is the flipped diagonal.
PICTURE. The orange diagonal from Step 3, and beneath it 's behaviour row with every cell flipped (H↔L). Arrows show each flip. agrees with no program at its own column.

Step 5 — Feed its own code: run
WHAT. Since is a program, and programs are strings (Step 1), we may run on the input . We now trace and hit the trap.
WHY. was designed to disagree with the diagonal everywhere, including at its own cell. So we point at the one cell it cannot escape: itself. What does the table say cell should be? Whatever predicts. And was built to contradict exactly that.
PICTURE. A flowchart of the single run : it calls ; the two output branches (green HALT, red LOOP) each loop back to a contradiction stamp.

Let us walk both possible answers of — there are only two, and we must cover each.
Step 6 — Case A: says HALT
WHAT. Suppose . By 's definition, this is claiming " halts on ". But now trace 's own code with this answer: the if H(P,P)==HALT branch is taken, so executes loop forever. Therefore loops — it does not halt.
WHY. We are testing whether 's prediction can be self-consistent. It cannot: predicted "halts", the machine actually loops. is wrong.
PICTURE. The green HALT wire out of ; following 's code it lands on loop forever; a red ✗ marks the clash between the prediction (halts) and the reality (loops).

Step 7 — Case B: says LOOP
WHAT. Suppose instead , i.e. claims " loops on ". Trace : the if condition is false, so the else branch runs — executes halt. Therefore halts.
WHY. Again the prediction and the reality are opposite. predicted "loops", the machine actually halts. is wrong here too.
PICTURE. The red LOOP wire out of ; following 's code it lands on halt; a red ✗ marks the clash (predicted loops, actually halts).

Step 8 — Collapse the two cases into one impossible sentence
WHAT. Chain Case A and Case B together. Case B says halts exactly when ; and Case A says is forced precisely when loops. Putting the whole loop of implications on one line:
Reading each link: the left is 's code (halting means the else branch ran, which needs to have said LOOP). The right is the meaning of (that label means runs forever). Stripping the middle:
That is a statement equivalent to its own negation — like "this sentence is false". No truth value fits.
WHY. A thing cannot both halt and not-halt. The only ingredient we ever assumed was . Everything after (, running ) was legal construction. So the assumption is the culprit.
PICTURE. A circular chain of three boxes — " halts" → " said LOOP" → " loops" → back to " halts" — forming a closed contradiction ring, with a red lightning bolt where halts meets loops.

Step 9 — The degenerate case: "just simulate and watch" is not a decider
WHAT. A natural objection: "why bother with — just run on and see." Call this simulator . If halts, eventually notices and reports . But if loops forever, also runs forever and never reports anything.
WHY. This shows the boundary case matters. A decider must always halt with an answer. answers on the halting inputs but hangs on the looping ones — so is a recognizer (semi-decider), not a decider. is therefore recognizable but undecidable — a distinction lifted directly from Decidable vs Recognizable Languages.
PICTURE. Two timelines. Top: halts → simulator stops → outputs HALT ✓. Bottom: loops → simulator's clock spins forever → the LOOP answer never arrives (dashed, greyed out).

The one-picture summary
WHAT. One figure that compresses all nine steps: code-is-data → assume → the grid → flip the diagonal into → run → both wires die → the impossible sentence.
PICTURE. A left-to-right pipeline of the whole argument, ending in the red contradiction ring; the flipped-diagonal grid sits above as the visual heart.

Recall Feynman retelling of the whole walkthrough
Start with one small truth: a program is just text, so I can hand a program a copy of itself. Now pretend a magic box exists that always tells me, correctly, whether any program eventually stops. I imagine a giant table: rows are programs, columns are the same programs used as inputs, and each cell says "stops" or "runs forever". I only care about the diagonal — each program run on its own code. I build a sneaky program : it asks the box about a program running on itself, then does the opposite of the answer. Finally I show its own code. If the box says " stops", runs forever; if the box says " runs forever", stops. Either way the box is wrong — so " stops" and " runs forever" become the same thing, which is impossible. The only thing I ever guessed was the magic box, so the box can't exist. And if you object "just run it and watch" — that only works when the program does stop; if it loops, your watcher loops too and never says "runs forever", so watching is a recognizer, never a decider.
Recall
In cell of the grid, what question is being asked? ::: Does program halt when given its own code as input? What does do relative to 's prediction about on itself? ::: The exact opposite (predicted HALT → loops; predicted LOOP → halts). Which single assumption does the contradiction destroy? ::: That the total decider exists. Why is "simulate and watch" only a recognizer? ::: If the program loops forever the simulation also never halts, so it can never output LOOP. State the collapsed impossible sentence. ::: halts loops.