Archive for December, 2008

The Twelve Bugs of Christmas, via Ruby

Here’s a little bit of post-Christmas fun, based on the Twelve Days of Christmas.

bugs = %{
     Tell them it's a feature
     Say it's not supported
     Change the documentation
     Blame it on the hardware
     Find a way around it
     Say they need an upgrade
     Reinstall the software
     Ask for a dump
     Run with the debugger
     Try to reproduce it
     Ask them how they did it and
     See if they can do it again.
}.strip.split("\n").map { |bug| bug.strip }.reverse

days = %w[first second third fourth fifth sixth seventh eighth ninth tenth eleventh twelfth]

0.upto(11) do |day_num|
  puts "For the #{days[day_num]} bug of Christmas, my manager said to me"
  day_num.downto(0) do |bug_num|
    puts bugs[bug_num]
  end
  puts
end

Simplifying Boolean Expressions

(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.

if (someCondition) {
    return true;
}
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:

return someCondition;

The same goes for assigning a variable. This:

bool result = false;
if (someCondition) {
    result = true;
}

…is the same as this:

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:

if (someCondition) {
    return false;
}
return true;

// is the same as:
return !someCondition;

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

if (condition1) {
    if (condition2) {
        return true;
    }
    return false;
}
return false;

// is basically:
return condition1 && condition2;

And…

if (condition1) {
    return true;
}
else if (condition2) {
   return true;
}
else {
   return false;
}

// is just:
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.

function contrivedYetNasty(hasYirmish, isNingle, amount) {
    var tooMuch = false;
    if (amount > 100) {
        tooMuch = true;
    }

    var foo = false;
    if (hasYirmish == false) {
        if (!!tooMuch) {
          foo = true;
        }
        else {
          foo = false;
        }
    }
    else {
        foo = true;
    }

    if (isNingle == true) {
        if (foo == false) {
            return false;
        }
        else {
            return true;
        }
    }
    else {
        return false;
    }
}

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:

assert(false, contrivedYetNasty(false, false, 0))
assert(true,  contrivedYetNasty(false, true, 110))
assert(false, contrivedYetNasty(true, false, 0))
assert(true,  contrivedYetNasty(true, true, 110))  

assert(false, contrivedYetNasty(false, false, 0))
assert(true,  contrivedYetNasty(false, true, 110))
assert(false, contrivedYetNasty(true, false, 0))
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.

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:

if (hasYirmish == false) {
    foo = tooMuch;
}
else {
    foo = true;
}

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:

var foo = hasYirmish || tooMuch;

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

function contrivedYetNasty(hasYirmish, isNingle, amount) {
    var tooMuch = amount > 100;
    var foo = hasYirmish || tooMuch;

    if (isNingle == true) {
        if (foo == false) {
            return false;
        }
        else {
            return true;
        }
    }
    else {
        return false;
    }
}

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.

if (isNingle == true) {
    return foo;
}
else {
    return false;
}

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.

return isNingle && foo;

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

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

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

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

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.


Say Hello

danbernier [at] gmail [dot] com
Twitter @danbernier
Hartford.rb
LinkedIn

Tweeting:

I’m a BackPack fan

Backpack

Categories