(Apologies if this material seems elementary, but I’ve found enough code to make me think it should be talked about.)

I found some C# today that looked kind of like this.

1 if (someCondition) {
2     return true;
3 }
4 return false;

This code says the author missed some key points about booleans. You can find it in almost any language.

Any code that fits into an if or while eventually becomes a boolean.  Using an if to “return true, else false” is redundant – just return the condition. That code can be simplified down to this one-liner:

1 return someCondition;

The same goes for assigning a variable. This:

1 bool result = false;
2 if (someCondition) {
3     result = true;
4 }

…is the same as this:

1 bool result = someCondition;

(If you feel the longer version is clearer, as some do, I respectfully disagree with you, but that’s a different point, and I’m not interested in debating preferences.  You can probably stop reading here, but thanks for stopping by.)

What if your boolean values are swapped? You can invert your condition:

1 if (someCondition) {
2     return false;
3 }
4 return true;
5 
6 // is the same as:
7 return !someCondition;

As the nesting gets deeper, it gets hairier, but it can still be tamed:

 1 if (condition1) {
 2     if (condition2) {
 3         return true;
 4     }
 5     return false;
 6 }
 7 return false;
 8 
 9 // is basically:
10 return condition1 && condition2;

And…

 1 if (condition1) {
 2     return true;
 3 }
 4 else if (condition2) {
 5    return true;
 6 }
 7 else {
 8    return false;
 9 }
10 
11 // is just:
12 return condition1 || condition2;

There are many other ways to tame a wild boolean – follow that link, and check the first table. It’s like simplifying an algebraic equation: x+0 is always x, and y && true is always y.

An Example

Let’s work through a contrived, yet nasty, example, to see how some of this works.

 1 function contrivedYetNasty(hasYirmish, isNingle, amount) {
 2     var tooMuch = false;
 3     if (amount > 100) {
 4         tooMuch = true;
 5     }
 6 
 7     var foo = false;
 8     if (hasYirmish == false) {
 9         if (!!tooMuch) {
10           foo = true;
11         }
12         else {
13           foo = false;
14         }
15     }
16     else {
17         foo = true;
18     }
19 
20     if (isNingle == true) {
21         if (foo == false) {
22             return false;
23         }
24         else {
25             return true;
26         }
27     }
28     else {
29         return false;
30     }
31 }

I have no idea what this does, but it’s nasty (which is often the situation with legacy code). These handy unit tests tell us how it behaves:

1 assert(false, contrivedYetNasty(false, false, 0))
2 assert(true,  contrivedYetNasty(false, true, 110))
3 assert(false, contrivedYetNasty(true, false, 0))
4 assert(true,  contrivedYetNasty(true, true, 110))  
5 
6 assert(false, contrivedYetNasty(false, false, 0))
7 assert(true,  contrivedYetNasty(false, true, 110))
8 assert(false, contrivedYetNasty(true, false, 0))
9 assert(true,  contrivedYetNasty(true, true, 110))

First, let’s tackle tooMuch. It’s false, but if amount is over 100, then it’s true. If it always has the same truthiness as amount > 100, then it’s equivalent to amount > 100. Let’s write it that way.

1 var tooMuch = amount > 100;

The tests pass.

Next, let’s look inside the if (hasYirmish == false) block, lines 9 - 14 in the original. First, !!tooMuch is a double-negative: the first ! cancels out the second. We can just say if (tooMuch). “If tooMuch is true, foo is true; else (if tooMuch is false), foo is false.” So foo is the same as tooMuch, and we can rewrite the block like this:

1 if (hasYirmish == false) {
2     foo = tooMuch;
3 }
4 else {
5     foo = true;
6 }

Tests pass.

“If hasYirmish is false, foo is tooMuch; else, foo is true.” This is just like a boolean OR expression. When a || b is evaluated, if a is true, the expression evaluates to true, without even checking b; but if a is false, then the expression evaluates to the value of b. And that’s exactly what we want here. That block just becomes:

1 var foo = hasYirmish || tooMuch;

The tests still pass. So far, we’re down to this:

 1 function contrivedYetNasty(hasYirmish, isNingle, amount) {
 2     var tooMuch = amount > 100;
 3     var foo = hasYirmish || tooMuch;
 4 
 5     if (isNingle == true) {
 6         if (foo == false) {
 7             return false;
 8         }
 9         else {
10             return true;
11         }
12     }
13     else {
14         return false;
15     }
16 }

Not bad!

Inside the isNingle == false block, on lines 6 - 11 above, we have: “if foo is false, return false; else (if it’s true), return true.” Again, we just want to return the value of foo. Let’s re-write it that way, test it (they pass), and take a look at the isNingle == true block.

1 if (isNingle == true) {
2     return foo;
3 }
4 else {
5     return false;
6 }

Now, we have a similar situation to when we introduced the OR expression, but it’s slightly different. If isNingle is false, the whole thing is false; if it’s true, then it’s the value of foo. Sounds like an AND expression. Let’s try it.

1 return isNingle && foo;

The tests still pass. Let’s step back and look at our progress:

1 function contrivedYetNasty(hasYirmish, isNingle, amount) {
2     var tooMuch = amount > 100;
3     var foo = hasYirmish || tooMuch;
4     return isNingle && foo;
5 }

From 31 lines down to five, and it’s actually readable. We can in-line those variables, and it gets even clearer:

1 function contrivedYetNasty(hasYirmish, isNingle, amount) {
2     return isNingle && (hasYirmish || amount > 100);
3 }

It returns true “if isNingle, and either it hasYirmish, or amount is over 100.” Much better.

Beyond the Basics

Once you’re comfortable with simplifying boolean expressions, there’s a number of rules you can employ to refactor nastier boolean expressions. Most of them are easy to remember, and can be easily illustrated in real-life terms. Meet DeMorgan:

  • !(a || b) == !a && !b. “It’s not red or green” is the same as “It’s not red, and it’s not green.”
  • !(a && b) == !a || !b. “I’m not rich and handsome” is true if I’m not rich, OR if I’m not handsome. (Or if I’m neither.)

These rules are part of a larger topic called Boolean algebra, which is useful for simplifying circuits, and (of course) programming. At my university, Boolean algebra was taught in Discrete Math, which was required for CS majors. Maybe programmers without a CS degree have a harder time with booleans because they missed this class, but the good news is, it’s easy enough to pick up.