How to Make the Switch Statement Suck Less

How to Make the Switch Statement Suck Less
   The switch statement sucks. I firmly believe that the only reason it is still haunting C-style languages these days is that it has been with us since ancient times. The switch statement has limited usefulness, remarkably heavy syntax and is likely to produce errors.

The Switch Statement Can Easily Be Replaced by If Statements


   The first problem with the switch statement is that it can be replaced by an if statements without significant loss of clarity. In fact switch is significantly less powerful than if/else if/else because if conditions can be more complex and switch only compares values to constants. I am not saying that there are no cases where switch looks better than if but even then the value we gain is quite limited for the price we pay in the form of language complexity. Obviously if we have already paid the price there is no reason to not use it if it makes sense.

The Switch Statement Has Heavy Syntax


   Just look at this syntax:

switch (day)
{
   case WeekDay.Monday:
       Console.WriteLine("Monday");
       break;
   case WeekDay.Tuesday:
       Console.WriteLine("Tuesday");
       break;
   case WeekDay.Wednesday:
       Console.WriteLine("Wednesday");
       break;
   case WeekDay.Thursday:
       Console.WriteLine("Thursday");
       break;
   case WeekDay.Friday:
       Console.WriteLine("Friday");
       break;
   case WeekDay.Saturday:
   case WeekDay.Sunday:
       Console.WriteLine("Weekend");
       break;
   default:
       Console.WriteLine("Unknown day");
       break;
}

It is littered with keywords (switch, case, break, default) and syntactic tokens like braces, columns and parenthesis. I know very few statements that are so heavy on syntax and all of them are language specific (for example Java anonymous classes). In addition the switch statement has one very peculiar feature that is an exception from the rules of the C-style syntax – every case introduces a multi-line block without braces. Implicit blocks exist in C-style languages but they are always single-statement like the implicit blocks that can be used if your loop body is just a single statement.

It Is Easy to Make Mistakes with the Switch Statement


   The most common mistakes in some popular C-style languages (C/C++, Java) is to forget the break at the end of a case statement. This is known as fall-through and is especially nasty since in most cases it will not even result in runtime error but in broken data.

The Switch Statement in C#


   C# prevents this most common mistake by requiring a break for every non-empty case label. This leaves us with the obvious question what to do if the fall-through is the desired behavior. First of all it should be obvious that fall-through is rarely the desired behavior so it should not be the default. The actual problem is easily solved if we know that C# does not require specifically break to be used with non-empty case labels but requires some kind of unconditional jump. The unconditional jump is most commonly a break statement but it can also be a return, throw, goto or even a continue statement for an enclosing loop. To solve the problem we simply use a goto like this:

switch (day)
{
   case WeekDay.Monday:
   case WeekDay.Tuesday:
   case WeekDay.Wednesday:
   case WeekDay.Thursday:
   case WeekDay.Friday:
       Console.WriteLine("Work day");
       break;
   case WeekDay.Saturday:
       Console.WriteLine("First day of");
       goto case WeekDay.Sunday;
   case WeekDay.Sunday:
       Console.WriteLine("Weekend");
       break;
}

This solves one problem but there is another. If a switch has no sensible default the default case can be skipped. This is especially dangerous with enums because if a new enum value is added later it would result in silent error where no case will be executed but potentially no error will occur. Ideally we want a compile-time error in this case like the one provided by F#'s match statement but obviously we cannot achieve this. What we can achieve is turn the silent error into a runtime error by adding a default label that throws an exception. Looking at a switch statement that handles the famous Boolean enum.

switch(b)
{
   case Bool.True:
       //Do something
       break;
   case Bool.False:
   case Bool.FileNotFound:
       //Do something else
       break;
   default:
        throw new Exception("Unexpected Boolean value");
       //note we don’t need a break after a throw
}

   This way if we add another Boolean value to the enum like AccessDenied we would at least get runtime error if we forget to change the switch statement which is certainly better than the silent error that would happen if we did not have a default.

   Yes, I do realize this was incredibly long way to say "Always write a default case to your switch statements and throw an exception if you do not have suitable logic".
Tags:   english programming 
Posted by:   Stilgar
16:03 04.11.2013

Comments:

First Previous 1 Next Last 

Posted by   Bubble (Unregistered)   on   20:01 04.11.2013

Man please put a searchbox in your blog..

Posted by   Stilgar   on   20:05 04.11.2013

I am too lazy to do that but you can always use a search engine and add site:sietch.net at the end of your query and you have a search box :)

Posted by   Guest (Unregistered)   on   23:17 09.12.2013

I thought this was not a blog..?

Posted by   Stilgar   on   01:10 10.12.2013

That's why it doesn't have a search box

Posted by   JOKe (Unregistered)   on   01:38 07.01.2014

(like) on Stilgar last comment (because its also not facebook so I can like it only like that

Posted by   gophie (Unregistered)   on   16:40 17.03.2014

Dude, checkout the switch statement in Go. Instead of making the brake in each case required (which is retarded...) they've made it implicit. So if you want to fall through, you have the `fallthrough` keyword, otherwise everything works as expected.

Problem fucking solved :)

Posted by   Stilgar   on   17:00 17.03.2014

I am perfectly sure that the C# designers were aware that making the break required is retarded but they were aiming for compatibility and familiarity with C++ and Java. In C# the goto serves as fallthrough keyword.

BTW does the Go switch do anything more than C/C++/C#/Java switch like for example pattern matching?

Posted by   Guest (Unregistered)   on   18:56 16.07.2015

I've been a long time VB / VBA / SQL programmer, but just learning JAVA this summer in college. I guess what ticks me off the most is that JAVA is still very much lower-level C programming in syntax instead of a more upper-level language.

I really get tired of writing things like ...

if ( ( this == 1 ) || ( that == 1 ) )

... when in VB / VBA you write things like...

if this = 1 or that = 1

... it's just more human-readable the second way.

Likewise, they really need a "between" operator. To do that in JAVA you have to do ...

if ( ( this >= 500 ) && ( this <= 1000 ) )

... wtf? It's cleaner to be able to write...

if ( this between 500 and 1000 )

... the whole point of the compiler is to let humans write something legible, and then translate that into what the machine wants to see. When I write Java I feel like I'm living in 1980 all over again. The luxuries of a high-level languge aren't there, yet JAVA is becoming this pervasive thing... so much so that colleges (esp mine) are teaching it as the "intro to programming" class (and students are dropping like flies, because it's too confusing as an intro programming language).

The switch statement has especially annoyed me. VB/VBA have case/select statement, so I thought it worked just like that... until my program kept blowing up. Then I looked into it, and switch needs a "break" after every time it should exit ?!?!?!?

Why? That's outlandish!

In VB / VBA the syntax for a case/select (switch equivilent) is something like...


Select Case LNumber
  Case 1, 2
     LRegionName = "North"
  Case 3, 4, 5
     LRegionName = "South"
  Case 6
     LRegionName = "East"
  Case 7, 11
     LRegionName = "West"
  Case Else
     LRegionName = "Unknown"

End Select

... when the case select runs, you get one result and you hit all possible options (sometimes your "else" part is used as an error trap, other times it's used to flag the majority possibilities with the minority/exceptions getting special treatment from earlier parts of the case/select).

The point is, there is no "analyze all parts of the case/select, because you didn't put a break". It automatically breaks out of the statement when it finds the right thing ... and it breaks out automatically if nothing matches. The point is, the statement runs once, and you don't get things multi-evaluated because you forgot to include some break statements. You don't have to manually break out of it.

I'm not here saying VB/VBA is better then JAVA. I'm just saying that coming from a higher-level language like VB/VBA to something like JAVA, which is dug deep in it's C roots in its syntax, it's just ... odd seeing what you have to go through in JAVA to do mundane stuff. It's the 21st century, and they can't code in some higher-level operators to make JAVA more readable? They could. They could make it where you can use old-school C-style syntax and higher level things like "or" and "between" and stuff. But, they don't. So, it keeps looking like this archaic language that drives some folks nuts.

First Previous 1 Next Last 


Post as:



Post a comment: