Skip to content

Two Guards, One Guard

A truth table can prove that a tangled test and a plain one behave identically, which lets you swap one for the other.

Here is a line from a real game loop:

IF NOT (dead OR finished) THEN
  CALL keepPlaying
END

You can work out what it means, but it takes a moment. Two negatives fighting each other: not one thing or the other thing.

Now here is another line:

IF alive AND unfinished THEN
  CALL keepPlaying
END

That one you read at a glance. The claim of this unit is that they are the same test, and that you can prove it rather than take it on trust.

Proving it

alive is NOT dead, and unfinished is NOT finished. So the claim is:

NOT (dead OR finished) is NOT dead AND NOT finished

Build both columns and compare:

deadfinishedNOT (dead OR finished)NOT dead AND NOT finished
0011
0100
1000
1100
Every row agrees, so the two tests cannot be told apart by any program.

Every row matches. Not most rows. Every row, and the table lists all of them, so there is no case left where they could differ.

That is a proof. The two lines are interchangeable, and you may write whichever one reads better.

The rule behind it

This is not a one-off. It works the other way round too:

ABNOT (A AND B)NOT A OR NOT B
0011
0111
1011
1100
The same trade, with AND and OR the other way round.

Both together are called De Morgan’s laws, after the mathematician who wrote them down:

  • NOT (A AND B) is the same as NOT A OR NOT B
  • NOT (A OR B) is the same as NOT A AND NOT B

The pattern is short enough to keep in your head. Push the NOT inwards, and AND swaps with OR.

What it is for

Two things, and the second is the one that pays.

Untangling. A NOT in front of a bracket is hard to read. Push it in, and often the double negatives cancel and leave you a line that says what it means.

Choosing your side. Sometimes the positive version is clearer, sometimes the negative one. De Morgan’s lets you pick without changing behaviour. A guard is easier to trust when it is phrased the way you think about the problem.

When the tables disagree

The interesting case is when you build both columns and they do not match.

That is not a failure. It means the two lines are genuinely different tests, and you have just found out which cases tell them apart. Look at the rows that differ, because one of them is a bug you were about to ship.

This is the whole method: when you are unsure whether two versions behave the same, do not squint at them. Build both columns and read across.

When it’s wrong, see why

  • You dropped a NOT while pushing it in. Every term inside the bracket gets one. NOT (A AND B) is NOT A OR NOT B, not NOT A OR B.
  • You forgot to swap the joining word. Pushing a NOT in turns AND into OR and back. Leaving it alone gives a different test that happens to look right.
  • The columns disagree in one row. Trust the table. Find that case in the game and decide which behaviour you want.

What you’ve learnt

  • Two tests that agree in every row are the same test, and you can swap them freely.
  • De Morgan’s laws: push a NOT inside a bracket and AND swaps with OR.
  • The point is readable guards: say a condition the way you think about it.
  • Columns that disagree have shown you a case worth looking at.

Where this leaves you

You can write down every case a test has, compare two tests honestly, and rewrite one into the other without changing what it does. That is enough to keep any IF you write under control.

The tables have a second life, though. Every one of them can be built out of wire. Once you have met binary in Counting in Twos, Gates and the Adder picks these same three tables up and makes them add.