88

Why does C# allow code blocks without a preceding statement (e.g. if, else, for, while)?

void Main()
{
    {   // any sense in this?
        Console.Write("foo");
    }
}
Rob Kennedy
  • 161,384
  • 21
  • 275
  • 467
Seldon
  • 1,395
  • 1
  • 11
  • 19
  • 71
    Is there any reason it _shouldn't_? – Jamiec May 26 '11 at 10:06
  • 2
    @Jamiec, good point, I hate all "Why" questions, I dont know what they want to prove anyway, it doesnt hurt anyone though. – Akash Kava May 26 '11 at 10:08
  • 32
    But as answers show it has more meaning than just "doesn't hurt, so let allow it". This is a point of asking such questions. – Seldon May 26 '11 at 10:13
  • The example block _does_ have a statement... Is there a better name for this? – H H May 26 '11 at 10:31
  • @Henk Holterman: Not that I can find... the spec calls `using`, `if`, `for`, `while`, `do-while`, etc statements. There *are* [different categories](http://msdn.microsoft.com/en-us/library/xt4z8b0f%28v=vs.71%29.aspx), but not an umbrella term for statements that have their own code blocks. – BoltClock May 26 '11 at 10:36
  • 8
    +1 question sounds innocent enough, but answers have really taught me something valuable – Nicolas78 May 26 '11 at 11:34
  • I hope I made the question clearer with my edit. I'm not sure what these "statements" can be collectively known as either. – BoltClock May 26 '11 at 12:22
  • 7
    @Akash: Without asking why, we will never get better. – richard May 26 '11 at 14:30
  • 1
    @Richard, Well I will consider reading MSDN, C# Language Specifications and consider enhancing some fundamental then just coming here and asking Why. Why will never make anyone better, but reading/understanding will make it. If one knows how compilers work, what is importance of scope, analysis done at compilation level and linking level, you will never need to ask any Why. – Akash Kava May 26 '11 at 15:12
  • 2
    Don't know why simple questions got more upvotes on SO and answers of that questions got even more upvotes. – Vivart May 26 '11 at 15:34
  • 7
    @Akash: That seems like a high-brow elitist attitude. People always have questions, and if there is no reason to ask why, then there is no point in having SO. This site isn't so much for having people solve our immediate problems (though that does happen), but to provide a repository of questions and answers that will help us all be better programmers. SO is for asking WHY! :-) – richard May 26 '11 at 16:03
  • @Vivart: The reason is that in todays programming world, so much is syntactic sugar, magic, and otherwise not obvious or explicit, and so sometimes it is the simplest things that get the most "Ah-ha!" moments from the rest of us simple programmers. :-) – richard May 26 '11 at 16:05
  • 1
    @jamie yes, there is. Read the example uses in the answers. Most, if not all, are examples of bad design. – Jon Strayer May 26 '11 at 16:14
  • I don't understand why my answer got so many upvotes, badges and the checkmark. I'm not even remotely answering the question of why... :S (Well, perhaps I got the checkmark and 80% of the votes just for being the accepted answer, but still...) – BoltClock May 26 '11 at 16:53
  • 3
    @Bolt: The question itself got 27 upvotes. It must be one of the more fundamental C# problems plaguing the community. – H H May 26 '11 at 17:09
  • 1
    I never know if the OP simply wants the reputation or is asking an honest question. – user7116 May 26 '11 at 17:45
  • 1
    Can someone please explain to me what is ambiguous, vague, incomplete, broad or rhetorical in this question? It is not an open ended question, it has a specific answer to it, and it is clearly laid out as to what is being asked. – mockobject May 26 '11 at 18:10
  • 1
    @mockobject: C# has thousands of features and warts that you could place 'why' in front. If the Q had been 'what does a lone {} pair do' I might have tried to dig up a dupe first. – H H May 26 '11 at 18:23
  • 4
    To those that closed this question, very draconian. Obviously many people learned something from this question, so it was helpful (which is what SO is supposed to be). Maybe instead of closing it, you could have helped the OP rephrase the question. The question wasn't necessarily phrased very well, but it obviously resonated with a lot of people. SO isn't an academic endevour, it's for helping people be better programmers. – richard May 26 '11 at 20:33
  • @Richard: I think what the close voters took issue with was precisely how it resonates with many people... coupled with its "why does X language do this"-ness. I honestly had no idea those were grounds for closure, but I dare not cast a reopen vote. – BoltClock May 26 '11 at 23:43
  • 1
    @BoltClock: you've got as much right to reopen as I did to close :) I chose to close it as it seemed the OP did not bother to do any research. – user7116 May 27 '11 at 03:14

9 Answers9

149

The { ... } has at least the side-effect of introducing a new scope for local variables.

I tend to use them in switch statements to provide a different scope for each case and in this way allowing me to define local variable with the same name at closest possible location of their use and to also denote that they are only valid at the case level.

João Angelo
  • 56,552
  • 12
  • 145
  • 147
  • 6
    It's worth reading http://blogs.msdn.com/b/ericlippert/archive/2009/08/03/what-s-the-difference-part-two-scope-vs-declaration-space-vs-lifetime.aspx – Dan Diplo May 26 '11 at 13:36
  • 6
    If you need scopes in your cases, they're too big! Extract Method. – Jay Bazuzi May 26 '11 at 14:03
  • 21
    @Jay Bazuzi, just because I want to have a local variable with the same name in more than one case doesn't mean they have to be huge. You're just jumping to _huge_ conclusions... :) – João Angelo May 26 '11 at 14:35
  • 1
    @BoltClock, thanks, I just need some more questions about `{}` to keep those gold badges coming... :) – João Angelo Sep 01 '11 at 21:38
90

In the context you give, there is no significance. Writing a constant string to the console is going to work the same way anywhere in program flow.1

Instead, you typically use them to restrict the scope of some local variables. This is further elaborated here and here. Look at João Angelo’s answer and Chris Wallis’s answer for brief examples. I believe the same applies to some other languages with C-style syntax as well, not that they’d be relevant to this question though.


1 Unless, of course, you decide to try to be funny and create your own Console class, with a Write() method that does something entirely unexpected.

Community
  • 1
  • 1
BoltClock
  • 700,868
  • 160
  • 1,392
  • 1,356
  • 24
    Re: other languages: usually, but not always. JavaScript is a notable exception; declaring a local variable in a particular block does not scope the variable to the block. – Eric Lippert May 26 '11 at 15:23
  • @EricLippert: In C#, does declaring a variable within a block cause the variable to be scoped from the perspective of the run-time? From what I can tell, variables' lifetimes are often not bounded by scoping blocks, a fact which is observable in mixed-language projects if the first thing done with a variable in a loop is to pass it as an `out` parameter to an interface implementation written in another language, and that implementation reads the variable before writing it. – supercat Jul 14 '15 at 17:25
  • And in C++, because of RAII instead of GC, it is far more useful. – Deduplicator Dec 23 '15 at 01:44
  • In C++, it acts much like a try/catch block, so variables and classes declared within that scope pop off the stack when you leave that scope. This helps prevent name collisions and reduces the function's memory footprint. It also removes those variables from code editor's auto-completion. Often I find try/catch blocks more useful. – Kit10 May 07 '20 at 15:03
57

It is not so much a feature of C# than it is a logical side-effect of many C syntax languages that use braces to define scope.

In your example the braces have no effect at all, but in the following code they define the scope, and therefore the visibility, of a variable:

This is allowed as i falls out of scope in the first block and is defined again in the next:

{
    {
        int i = 0;
    }

    {
        int i = 0;
    }
}

This is not allowed as i has fallen out of scope and is no longer visible in the outer scope:

{
    {
        int i = 0;
    }

    i = 1;
}

And so on and so on.

Chris Wallis
  • 1,263
  • 8
  • 20
  • 1
    I've read about disparities in bracket nomenclature in various flavors of English, but in which flavor are `{}` known as parentheses? – BoltClock May 26 '11 at 10:46
  • Good question! I guess a mentor of mine planted it in my brain a decade ago. I should probably be calling them 'curly brackets' or 'braces'. Each to their own... http://en.wikipedia.org/wiki/Bracket#Parentheses_.28_.29.2C_.5B_.5D.2C_or_.7B_.7D – Chris Wallis May 26 '11 at 10:52
  • 10
    In my vocab '(' = parenthesis, '{' = brace, '[' = square brackets – pb. May 26 '11 at 12:18
  • Hang on, I would call them a curly bracket, and Wikipedia includes that naming. The Oxford English Dictionary defines this use of bracket as: `One of two marks of the form [ ] or ( ), and in mathematical use also {}, used for enclosing a word or number of words, a portion of a mathematical formula, or the like, so as to separate it from the context;` In any case they are not parentheses, but 'curly bracket' seems OK. – dumbledad Jan 31 '13 at 16:02
  • IME, "curly braces" and "square brackets". – cp.engr Sep 14 '16 at 16:25
18

I consider {} as a statement that can contain several statements.

Consider an if statement that exists out of a boolean expression followed by one statement. This would work:

if (true) Console.Write("FooBar");

This would work as well:

if (true)
{
  Console.Write("Foo");
  Console.Write("Bar");
}

If I'm not mistaken this is called a block statement.

Since {} can contain other statements it can also contain other {}. The scope of a variable is defined by it's parent {} (block statement).

The point that I'm trying to make is that {} is just a statement, so it doesn't require an if or whatever...

RBaarda
  • 558
  • 3
  • 10
13

The general rule in C-syntax languages is "anything between { } should be treated as a single statement, and it can go wherever a single statement could":

  • After an if.
  • After a for, while or do.
  • Anywhere in code.

For all intents and purposes, it's as the language grammar included this:

     <statement> :== <definition of valid statement> | "{" <statement-list> "}"
<statement-list> :== <statement> | <statement-list> <statement>

That is, "a statement can be composed of (various things) or of an opening brace, followed by a statement list (which may include one or more statements), followed by a closed brace". I.E. "a { } block can replace any statement, anywhere". Including in the middle of code.

Not allowing a { } block anywhere a single statement can go would actually have made the language definition more complex.

Massimo
  • 1,520
  • 1
  • 19
  • 36
  • Someone just upped this answer (after 9 years), which wasn't actually a specific answer to this question, but much more a generic discussion. It may wery well have been superseded by the language and libraries.. But it was a pleasure anyway, thank you. – Massimo Jun 07 '20 at 03:03
1

Because C++ (and java) allowed code blocks without a preceding statement.

C++ allowed them because C did.

You could say it all comes down to the fact that USA programme language (C based) design won rather than European programme language (Modula-2 based) design.

(Control statements act on a single statement, statements can be groups to create new statements)

Ian Ringrose
  • 51,220
  • 55
  • 213
  • 317
1
// if (a == b)
// if (a != b)
{
    // do something
}
user202448
  • 2,552
  • 5
  • 22
  • 25
0

1Because...Its Maintain the Scope Area of the statement.. or Function, This is really useful for mane the large code..

{
    {
        // Here this 'i' is we can use for this scope only and out side of this scope we can't get this 'i' variable.

        int i = 0;
    }

    {
        int i = 0;
    }
}

enter image description here

Raj
  • 1,213
  • 2
  • 16
  • 34
0

You asked "why" C# allows code blocks without preceeding statements. The question "why" could also be interpreted as "what would be possible benefits of this construct?"

Personally, I use statement-less code blocks in C# where readability is greatly improved for other developers, while keeping in mind that the code block limits the scope of local variables. For example, consider the following code snippet, which is a lot easier to read thanks to the additional code blocks:

OrgUnit world = new OrgUnit() { Name = "World" };
{
    OrgUnit europe = new OrgUnit() { Name = "Europe" };
    world.SubUnits.Add(europe);
    {
        OrgUnit germany = new OrgUnit() { Name = "Germany" };
        europe.SubUnits.Add(germany);

        //...etc.
    }
}
//...commit structure to DB here

I'm aware that this could be solved more elegantly by using methods for each structure level. But then again, keep in mind that things like sample data seeders usually need to be quick.

So even though the code above is executed linearly, the code structure represents the "real-world" structure of the objects, thus making it easier for other developers to understand, maintain and extend.

Marco
  • 700
  • 5
  • 11