views:

13090

answers:

15

Switch statement fallthrough is one of my personal major reasons for loving switch vs. if/else if constructs. An example is in order here:

static string NumberToWords(int number)
{
    string[] numbers = new string[] 
        { "", "one", "two", "three", "four", "five", 
          "six", "seven", "eight", "nine" };
    string[] tens = new string[] 
        { "", "", "twenty", "thirty", "forty", "fifty", 
          "sixty", "seventy", "eighty", "ninety" };
    string[] teens = new string[]
        { "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen",
          "sixteen", "seventeen", "eighteen", "nineteen" };

    string ans = "";
    switch (number.ToString().Length)
    {
        case 3:
            ans += string.Format("{0} hundred and ", numbers[number / 100]);
        case 2:
            int t = (number / 10) % 10;
            if (t == 1)
            {
                ans += teens[number % 10];
                break;
            }
            else if (t > 1)
                ans += string.Format("{0}-", tens[t]);
        case 1:
            int o = number % 10;
            ans += numbers[o];

            break;
        default:
            throw new ArgumentException("number");
    }
    return ans;
}

The smart people are cringing because the string[]s should be declared outside the function: well, they are, this is just an example.

The compiler fails with the following error:

Control cannot fall through from one case label ('case 3:') to another
Control cannot fall through from one case label ('case 2:') to another

Why? And is there any way to get this sort of behaviour without having three ifs?

+3  A: 

They changed the switch statement (from C/Java/C++) behavior for c#. I guess the reasoning was that people forgot about the fall through and errors were caused. One book I read said to use goto to simulate, but this doesn't sound like a good solution to me.

Ken
C# supports goto, but not fallthrough? Wow. And it's not just those. C# is the only language that I know of that behaves this way.
Matthew Scharley
I didn't exactly like it at first, but "fall-thru" is really a recipe for disaster (especially amongst junior programmers.) As many have pointed out, C# still allows fall-thru for empty lines (which is the majority of cases.) "Kenny" posted a link that highlights elegant Goto use with switch-case.
Pretzel
It's not a huge deal in my opinion. 99% of the time I don't want a fall through and I have been burned by bugs in the past.
Ken
+1  A: 

A jump statement such as a break is required after each case block, including the last block whether it is a case statement or a default statement. With one exception, (unlike the C++ switch statement), C# does not support an implicit fall through from one case label to another. The one exception is if a case statement has no code.

-- C# switch() documentation

R. Bemrose
I realise this behaviour is documented, I want to know WHY it is the way it is, and any alternatives to get the old behaviour.
Matthew Scharley
+1  A: 

C# doesn't support fall through with switch/case statements. Not sure why, but there's really no support for it. Linkage

BFree
+6  A: 

They left out this behaviour by design to avoid when it was not used by will but caused problems.

It can be used only if there is no statement in the case part, like:

switch (whatever)
{
    case 1:
    case 2:
    case 3: boo; break;
}
Biri
+13  A: 

Switch fallthrough is historically one of the major source of bugs in modern softwares. The language designer decided to make it mandatory to jump at the end of the case, unless you are defaulting to the next case directly without processing.

switch(value)
{
    case 1:// this is still legal
    case 2:
}
Coincoin
I well never understand why that isn't "case 1, 2:"
BCS
@BCS Its because the case statement is actually a label.
David Pfeffer
@David Pfeffer: Yup it is, and so is `case 1, 2:` in languages that allow that. What I will never understand is why any modern language would't choose to allow that.
BCS
A: 

The example you give can be written more elegantly and especially more readable using if/else constructs. In so far i'm glad C# puts an end to fall-through switch statements.

steffenj
if I use elseif's then I'm duplicating code. I see this as a more than legitimate use of switch fallthrough. I appreciate that it can cause bugs too, but I still wouldn't condemn it as bad and leave the only alternative as goto.
Matthew Scharley
+6  A: 

You can 'goto case label' http://www.blackwasp.co.uk/CSharpGoto.aspx

kenny
A: 

You forgot to add the "break;" statement into case 3. In case 2 you wrote it into the if block. Therefore try this:

case 3:            
{
    ans += string.Format("{0} hundred and ", numbers[number / 100]);
    break;
}


case 2:            
{
    int t = (number / 10) % 10;            
    if (t == 1)            
    {                
        ans += teens[number % 10];                
    }            
    else if (t > 1)                
    {
        ans += string.Format("{0}-", tens[t]);        
    }
    break;
}

case 1:            
{
    int o = number % 10;            
    ans += numbers[o];            
    break;        
}

default:            
{
    throw new ArgumentException("number");
}
Marcus
This produces vastly wrong output. I left the switch statements out by design. The question is why the C# compiler sees this as an error when almost no other language has this restriction.
Matthew Scharley
+47  A: 

(Copy/paste of an answer I provided elsewhere)

Falling through switch-cases can be achieved by having no code in a case (see case 0), or using the special goto case (see case 1) or goto default (see case 2) forms:

switch (/*...*/) {
    case 0: // shares the exact same code as case 1
    case 1:
        // do something
        goto case 2;
    case 2:
        // do something else
        goto default;
    default:
        // do something entirely different
        break;
}
Alex Lyman
I think that, in this particular instance, goto is not considered harmful.
Thomas Owens
Damn - I've been programming with C# since the early days of 1.0, and I've *never* seen this until now. Just goes to show, you learn new things every day.
Erik Forbes
It's all good, Erik. The only reason /I/ knew about it is that I'm compiler theory nerd who read the ECMA-334 specs with a magnifying glass.
Alex Lyman
+4  A: 

The "why" is to avoid accidental fall-through, for which I'm grateful. This is a not uncommon source of bugs in C and pre-1.5 Java.

The workaround is to use goto, e.g.

switch (number.ToString().Length)
{
    case 3:
        ans += string.Format("{0} hundred and ", numbers[number / 100]);
        goto case 2;
    case 2:
    // Etc
}

The general design of switch/case is a little bit unfortunate in my view. It stuck too close to C - there are some useful changes which could be made in terms of scoping etc. Arguably a smarter switch which could do pattern matching etc would be helpful, but that's really changing from switch to "check a sequence of conditions" - at which point a different name would perhaps be called for.

Jon Skeet
This is the difference between switch and if/elseif in my mind. Switch is for checking various states of a single variable, whereas if/elseif can be used to check any number of things that connected, but not necessarily a single, or the same variable.
Matthew Scharley
Pattern matching in C# would be spectacular...
Erik Forbes
+2  A: 

In addition to the other answers, the switch statement can be reorganised by the compiler for performance purposes. This means that the order of cases you provide may be modified during optimisation.

BlackWasp
A: 

The goto was truly useful. Still, the fallthrough should have set out a warning, instead of an error.

It's not a warning. It's not supposed to compile, by definition.
JeffH
+1  A: 

After each case statement require break or goto statement even if it is a default case.

Shilpa gulati
A: 

Place break ; into each case

Khawar
If you are going to inject into a 2 year old post, please atleast have something decent to say that hasn't been mentioned a half dozen times.
Matthew Scharley
A: 

You can achieve fall through like c++ by the goto keyword.

EX:

switch(num)
{
   case 1:
      goto case 3;
   case 2:
      goto case 3;
   case 3:
      //do something
      break;
   case 4:
      //do something else
      break;
   case default:
      break;
}
Dai Tran