Pet programming peeves . . .

Case Construct often Misused to Implement a Table

Conrad Weisert, Information Disciplines, Inc., 29 January 1999

A growing phenomenon

In my recent advanced C++ or Java courses I've been seeing more and more student exercises where the switch . . . case construct implements a table. More surprisingly, a number of recent textbooks illustrate that practice, such as this Java example 1:

  public static String number(int digit) { 
       switch(digit) {
	   case 0: return("zero" )
    	   case 1: return("one"  )
	   case 2: return("two"  )
	   case 3: return("three")
	   case 4: return("four" )
	   case 5: return("five" )
	   case 6: return("six"  )
	   case 7: return("seven")
	   case 8: return("eight")
	   case 9: return("nine" )
         default: return("Not a digit");

An experienced programmer would have recognized that as a table and would have coded something like this:

  public static String number(int digit) { 
        String[] digitName  = {"zero", "one", "two"  , "three", "four",
                               "five", "six", "seven", "eight", "nine”};
        return (digit >= 0 && digit < 10) ? digitName[digit] : "Not a digit";

This example is particularly suited to an array implementation, because:

A more extreme example is this absurd one2:

   for (int i=0; i< s.length(); i++)
     switch(s.charAt[i]) {
       case '0':
       case '1':
       case '2':
       case '3':
       case '4':
       case '5':
       case '6':
       case '7':
       case '8':
       case '9':
         nNumberOfDigits++; break;

That one doesn't even need any kind of table. A reasonable C programmer might code:

    for (int i=0; i< s.length(); i++)
       isdigit(s.charAt[i]) ?  ++nNumberOfDigits : ++nNumberOfNonDigits;

What if the case constants don't form a dense set?

A slightly more subtle situation arises when the case constants are sparse, as in this C example3:

   switch(ch) {
      case 'a': case 'A'
        ++acnt; break;
      case 'e': case 'E'
        ++ecnt; break;
      case 'i': case 'I'
        ++icnt; break;
      case 'o': case 'O'
        ++ocnt; break;
      case 'u': case 'U'
        ++ucnt; break;

The main flaw here is the use of five separately named counters. What if we decide to count "y"s, too?

If a student turned in the above, I would counsel him or her to convert the sparse characters to dense integers and use an array of counters. Here's a reasonable revision:

       static char vowelTbl[] = "AEIOU";  
       ch = toupper(ch);
       int chx = strchr(vowelTbl,ch) - vowelTbl;

Even more reasonable would be to package the logic as a reusable isvowel function, analogous to the character classification functions in the standard C library.

Why is the array version preferable to the case version? For one thing it's much simpler to change; try adding "Y" or the Scandinavian "Ø", "Å", and "Æ", ; to both versions; try adding a second action, e.g. printing, to each case.

From a pedagogic point of view, we want the student to think naturally of generalizing the pattern, especially to avoid multiple separately named counters. The number of vowels isn't likely to grow, but the pattern is similar to situations that arise in everyday programming, where we do add new cases.

What about efficiency?

Do we lose more in converting the character to an integer than we gain in the simple subscripting operation? I doubt it in any reasonable implementation, and if time is ultra-critical, we can allocate space for all possible characters and use the character code value itself as the subscript, a technique used in some C library routines.

So when should we use the switch . . case construct?

Actually, switch . . . case is needed less often than many inexperienced programmers believe. The key criterion for its use is that we're doing something different for each of the cases -- a different pattern of code, not just doing the same thing to different variables.

1 Marty Hall: Core Web Programming, 1998, Prentice Hall, ISBN 0-13-625666-X, p. 307. Hall's book is an excellent tutorial. Presumably his purpose was just to show an easy example of how the language construct works, rather than to recommend the technique, but we wish he had chosen a more worthy example.

2 Stephen R. Davis: Learn Java Now, 1996, Microsoft Press, p. 27.

3 Stanley Lippman: C++ Primer, p 207.

Last modified (minor correction) March 11, 2017

Return to C++ topics
Return to technical articles
Return to Table of contents.