56

I'm curious about this thing... see example:

switch(x)
{
    case(a):
        {
        //do stuff
        }
        break;
    case(b):
        //do stuff
        break;
}

All my life I've done it like case b, but since C# allows me to use it, and Visual Studio allows me to collapse that thing, I am curious - what is the real difference between case a (with braces) and case b?

JYelton
  • 35,664
  • 27
  • 132
  • 191
Wish
  • 1,594
  • 1
  • 18
  • 36
  • 16
    There is no difference except that variables defined in case a are only visible in that block. – juergen d Apr 10 '12 at 19:40
  • 3
    Nothing really. It's just that sometimes you want to create and use objects that are scoped to the case. Without brackets anything you define there has wider scope you see. – Robinson Apr 10 '12 at 19:40
  • 1
    Not what you asked, but I find long `case` blocks hard to read. If I need scoping or any other complexity, it gets a new method. – Jay Bazuzi Apr 11 '12 at 00:01
  • See also http://stackoverflow.com/q/3652408/292060 – goodeye Sep 08 '16 at 20:31

4 Answers4

78

A pair of braces (not brackets -- [] -- and not parentheses -- () -- but braces {}) with zero or more statements in them is a legal statement in C#, and therefore may appear anywhere that a statement may legally appear.

As others have pointed out, the typical reason for doing so is because such a statement introduces a new local variable declaration space, which then defines the scope of the local variables declared within it. (Recall that the "scope" of an element is the region of program text in which the element may be referred to by its unqualified name.)

I note that this is particularly interesting in a switch statement because the scoping rules in a switch are a little bit strange. For details of how strange they are, see "Case 3:" in my article on the subject:

http://ericlippert.com/2009/08/13/four-switch-oddities/

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
  • I've always felt disappointed that C# didn't introduce a smarter switch statement, as the C switch is one of the more bizarre and problematic constructs in programming. – Nate C-K Apr 17 '12 at 20:45
  • 6
    @NateC-K: C# *did* introduce a better switch statement! The C# designers closely examined the shortcomings of the C/C++ switch statement and improved upon it in many ways. For example: (1) The "no fall through" rule eliminates a common source of bugs. (2) You can switch on strings. (3) You can switch on nullable types. (4) The types of the case labels are checked to be compatible with the governing type of the switch. (5) "goto case 1" works properly, unlike in C++. And so on; in almost every conceivable way the C# switch is an improvement. – Eric Lippert Apr 17 '12 at 21:15
  • `You can switch on strings` is one of the more underappreciated features. So many languages don't allow that (e.g., Java or Delphi) and it turns a simple problem into a big if..elseif cascade. – Michael Stum Apr 17 '12 at 21:31
  • 2
    @phoog: I refer you to section 3.3.1 of The C++ Programming Language, 2nd edition (old, I know; it's the one I have handy), which states on page 103 "Note that a case label is not a suitable label for use in a goto statement." Perhaps C++ has added this feature while I wasn't paying attention, but it did not have the feature in 1991, when I was learning C++. – Eric Lippert Apr 17 '12 at 23:16
  • 1
    @EricLippert: True, there are some incremental improvements, and I do appreciate them; the C# switch statement is most definitely smarter, so the wording of my earlier statement was unfair. However, it left in the weird C syntax and consequent lack of appropriate scoping. Plus, now there are extra rules to remember that only apply to switch statements. For example, you have to add a break in each case, even though fall-through is forbidden so this is now purely vestigial. – Nate C-K Apr 19 '12 at 14:15
  • The most obvious way I can conceive of to make the switch statement better is to discard the label-oriented syntax entirely and do something like VB has instead; that is really what I meant. A complete break from the C syntax. The only real advantage I see to the C syntax is the ability to goto a case, and the uses of that are marginal at best; I think it would be pretty difficult to think of any uses of "goto case" that couldn't be accomplished with functional decomposition. – Nate C-K Apr 19 '12 at 14:21
71

Braces {} are used to define a scope for a set of operations. Bizarrely, the following will compile and work:

private void ConnectionStateChange(object sender, StateChangeEventArgs e)
{
    string s = "hi";
    switch(s)
    {
        case "hi":
            {
                int a = 1;
                a++;
            }
            {
                int a = 2;
                a++;
            }
            break;
    }

    {
        int a = 1;
        a++;
    }
    {
        int a = 2;
        a++;
    }
}

As you can see, in that one method I've created four variables, each called a. Each is entirely separate because, as local variables, they exist only within their own scope.

Does that make some sort of sense?

SShaheen
  • 1,012
  • 7
  • 21
Ian
  • 4,885
  • 4
  • 43
  • 65
  • well explained, really appreciate this! – Wish Apr 10 '12 at 19:48
  • 55
    Why bizarrely? That looks pretty normal (albeit contrived). – Joey Apr 10 '12 at 19:51
  • 35
    If having 4 different local variables named `a` in the same function looks pretty normal to you, you've been looking at the wrong code all this time. :) – cHao Apr 10 '12 at 19:54
  • 11
    Hence contrived, but introducing a new local scope isn't that unusual, imho. – Joey Apr 10 '12 at 20:04
  • One gotcha is that although JavaScript allows you to write the same block syntax, in that language it does not define a block, i.e. it does not delimit the scope of variables. – dumbledad Apr 10 '12 at 20:28
  • 12
    This should not be considered as bizarre at all. – jn1kk Apr 10 '12 at 20:52
  • The extra `{}` can actually be useful in C++, where reducing a scope of a variable causes its destructor to get called earlier. – dan04 Apr 10 '12 at 22:54
  • It's not that they exist only in their scope. It's that they can be referred to be their unqualified name only in their scope. – jason Apr 10 '12 at 23:12
  • @Jason: To which comment are you replying? – Adam Robinson Apr 11 '12 at 00:10
  • It's particularily useful, if you want to use different variables of the same name in different case blocks. (At least in Java it's forbidden otherwise.) Also I find it's looking nice having every case block covered in braces. – Kirill Rakhman Apr 11 '12 at 09:47
  • @Adam Robinson: To a statement in the answer. – jason Apr 11 '12 at 12:06
  • 2
    How sad that the accepted answer actually fails to explain (or, indeed, obviously to comprehend) why this is useful. – Konrad Rudolph Apr 11 '12 at 14:00
  • I understand Konrad. I could of made my explanation clearer. I was actually more concerned about not making any recommendations that could be considered stylistic. Personally I rarely have blocks of code in switch statements where reusing a variable name makes sense. the other answers here do go into more detail, so I think between us we've got it covered :) – Ian Apr 11 '12 at 21:26
30

It creates a new scope in which you can create new variables.

Daniel A. White
  • 187,200
  • 47
  • 362
  • 445
13

It creates new scope for variables you used. Scope of variables can be tricky sometimes. For instance in the code you posted;

switch(x)
{
    case(a):
        {
        int i = 0;
        }
        break;
    case(b):
        i = 1; // Error: The name 'i' doesn't exist in the current context
        break;
}

The error makes sense here as in case(b) variable a is accessed out of scope. Now on the other hand,

switch(x)
{
    case(a):
        {
        int i = 0;
        }
        break;
    case(b):
        int i = 1; // Error: A local variable named 'i' cannot be declared in this scope because it would give a different meaning to 'i', which is already used in a 'child' scope to denote something else
        break;
}

Above two errors look contradictory to each other. To get around this you should define the scope separately in both case statements,

switch(x)
{
    case(a):
        {
        int i = 0;
        }
        break;
    case(b):
        {
        int i = 1; // No error
        }
        break;
}

Eric Lippert shared a very good link to his blog to explain variable scopes in case statement. You should have a look at it.

Ilmari Karonen
  • 49,047
  • 9
  • 93
  • 153
ABH
  • 3,391
  • 23
  • 26