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:
| dead | finished | NOT (dead OR finished) | NOT dead AND NOT finished |
|---|---|---|---|
| 0 | 0 | 1 | 1 |
| 0 | 1 | 0 | 0 |
| 1 | 0 | 0 | 0 |
| 1 | 1 | 0 | 0 |
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:
| A | B | NOT (A AND B) | NOT A OR NOT B |
|---|---|---|---|
| 0 | 0 | 1 | 1 |
| 0 | 1 | 1 | 1 |
| 1 | 0 | 1 | 1 |
| 1 | 1 | 0 | 0 |
Both together are called De Morgan’s laws, after the mathematician who wrote them down:
NOT (A AND B)is the same asNOT A OR NOT BNOT (A OR B)is the same asNOT 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
NOTwhile pushing it in. Every term inside the bracket gets one.NOT (A AND B)isNOT A OR NOT B, notNOT A OR B. - You forgot to swap the joining word. Pushing a
NOTin turnsANDintoORand 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
NOTinside a bracket andANDswaps withOR. - 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.