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.

  • Foundations

Here is a guard for a game loop:

Code
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:

Code
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 under explicit assumptions rather than take it on trust.

Proving it

For this comparison, alive must equal NOT dead, and unfinished must equal NOT finished, using the same current Boolean values. These are names for the complementary answers, not independently stored flags that we hope agree. 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
Both expressions give the same Boolean output for every pair of fixed inputs.

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 proves equal Boolean results for the same input values. Under the stated complement assumptions, choose whichever wording reads better.

A table does not measure execution cost or establish a target language’s operand evaluation rules. If a test calls a job, changes state or can fail, check that language’s behaviour as well.

What if dead is TRUE but a separately stored alive flag is still TRUE?

With finished FALSE and unfinished TRUE, NOT (dead OR finished) is FALSE, but alive AND unfinished is TRUE. The stale flag breaks our complement assumption. De Morgan’s law has not failed; the renamed inputs no longer mean the same current facts.

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

  • Matching columns prove equal Boolean results for the same inputs, not every runtime behaviour.
  • 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 while preserving its Boolean result under the stated assumptions. Keep the actual input meanings and target-language rules in view.

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.

For a language-specific connection, Keep guessing checks the lower bound, upper bound and whole-number rule separately. Its complete BASIC listing and earlier entry help remain available; you do not need BASIC to finish these tables. Compare which cases its range checks reject before moving on.

The optional Game State Machine pattern shows why current facts and policy both matter: its transition table gives death priority over pause. It uses its own illustrative pseudocode, not our Foundations notation, and is not an execution record or required next lesson.

Sources

Sinclair Research, ZX Spectrum BASIC Programming, chapter 13, pp. 85–86, Conditions, describes AND, OR, NOT and De Morgan’s laws, then explains Sinclair BASIC’s numeric rules. Those target rules are distinct from the Boolean table notation used here.