In an earlier post, I showed how to rethink the traditional MS-SQL CURSOR logic pattern, to minimize the number of maintenance points for FETCH statements (The lost art of break and continue). That post covered the while() { … } loop. Another equally-useful variant is the do { … } while() loop, which also supports the break and continue statements.

The main difference between the two loop types is the number of guaranteed times the loop will execute. The while loop evaluates the boolean case at the beginning, so its content will not run at all if the initial boolean test evaluates to false.  For the SQL CURSOR example, these is useful when the number of rows to process is zero: the row handling logic doesn’t execute at all.

The do..while() loop is very useful for evaluating complex business logic using extensive branching (e.g. rate/tarff calculations).  The loop is guaranteed to always execute, and a break statement can exit the loop block at any time.  This is a great way to implement short-circuiting for evaluations (sometimes referred to as a trap-door sequence).  A trap door sequence is common in rate or tariff calculations, where a number of factors are evaluated to determine a specific rate or tariff.  Once the tariff is determined, the evaluation ends (the trap door) and the logic to further apply the calculated tariff continues.

An example of this type of logic using if() statements would look like this:

money Rate = -1.0;
 
if (Rate == -1.0 && TestCase1() == false) Rate = 2.0;
if (Rate == -1.0 && TestCase2())
{
  if (SubTest1ofTestCase2() == false)
  {
    if (SubTest2ofTestCase2() == true)
    {
      Rate = 1.754;
    }
    else Rate = 1.872;
  }
}
if (Rate == -1.0)  // when true, the rate is still indeterminate
{
  if (TestCase3() == false) Rate = 2.715;
}
 
if (Rate == -1.0)
{
  Rate = 2.772;   // apply a default, throw an error... whatever
}
 
// Rate application logic follows here

The penalty with this method, when a large number of evaluations is done, is that often the if(Rate == -1.0) statement has to end, and another if(Rate == -1.0) statement has to wrap the next set of logic that evaluates the next case.  If the rule set is long, the number of if(Rate == -1.0) wrappers will increase accordingly. There is no quick way out of the evaluation, just a way of stopping the next evaluation from occurring.

Since the do..while() loop evaluates at the end of the block, the code within the do loop is guaranteed to run at least once.  Set the ending evaluation to while(false) or until (true), and the code in the do…while() loop sequence only executes once.  Add the use of the break statement, and the do loop is perfectly suited for a block of code that requires a single pass and needs a quick exit: the trap-door sequence.  Have a look at the following example, which uses break statements, to solve the same problem.

money Rate = -1.0;
do
{
  if (Rate == -1.0 && TestCase1() == false) 
  {
    Rate = 2.0;
    break;
  }
  if (TestCase2())
  {
    if (SubTest1ofTestCase2() == false)
    {
      if (SubTest2ofTestCase2() == true)
      {
        Rate = 1.754;
        break;
    }
    else
    {
      Rate = 1.872;
      break;
    }
  }
  if (TestCase3() == false)
  {
    Rate = 2.715;
    break;
  }
  Rate = 2.772;   // apply a default, throw an error... whatever
} while (false);   // or until (true)... guarantees iteration will not occur.
 
// Rate application logic follows here
// ...

Many people would argue that the same effect can be established with GOTO statements and a label.  Even in my days programming modular code, I never liked the goto statement.  With line numbers in archaic BASIC code it made sense, but migrating it to use labels in object-oriented code seems to be carrying forward a hack: a way for old-school developers to find a way out of their code.

Break simply says the loop is ending, and is also a nice word choice to say the logic has a reason to “break out” of what it is doing.  The break statements, to me, are easier to follow as a developer inheriting someone else’s code base, and doesn’t break the rhythm of the logic.

This trap-door technique with the do { … } while() loop has proven very useful. I encourage you to try it.