In our introductory programming class, I try to reframe abstract logic into concrete spatial thinking. One way I do this is through the game Trux Falsy. Another way is through Venn diagrams. I want students to see how the AND operator creates an intersection, how the OR operator creates a union, and how DeMorgan’s Law flips an expression.

To support a visualization exercise in lecture today, I wrote this short Twoville program that generates all possible Venn diagrams for a 2-term boolean expression:

There are four regions in a two-term Venn diagram: the aMinusB region, the bMinusA region, the both region, and the neither region. In the code above, the venn function accepts a bit for each of these four regions. Each is colored according to its bit. With 4 regions, each either selected or unselected, we have $2^4 = 16$ possible diagrams.

When I first coded it up, I manually called the venn function with all possible bit configurations for these four regions:

During a refactoring, I decided to simplify this code by iterating through [0, 15] and extracting out the individual bits from the iterator. Twoville doesn’t yet support the shifting and masking operators, which are the usual means of extracting bits, and I was just about to add them. But then I thought, “Why not add the subscript operator to integers?” bitfield[0] would yield bit 0, bitfield[1] would yield bit 1, and so on.

Four lines of code later, I was able to condense my calls down to this:

for i to 16
venn(i[0], i[1], i[2], i[3], i % 4, i / 4)

## Comments