tags:

views:

325

answers:

9

In stumbled on this about a month ago.

In C# you can make a block inside of a method that is not attached to any other statement.

    public void TestMethod()
    {
        {
            string x = "test";
            string y = x;

            {
                int z = 42;
                int zz = z;
            }
        }
    }

This code compiles and runs just as if the braces inside the main method weren't there. Also notice the block inside of a block.

Is there a scenario where this would be valuable? I haven't found any yet, but am curious to hear of other people's findings.

+1  A: 

As far as I can see, it'd only be useful from an organizational standpoint. I can't really conceive of any logical value in doing that. Perhaps someone will have a proper example.

junkforce
+6  A: 

Scope and garbage collection: When you leave the unattached block, any variables declared in it go out of scope. That lets the garbage collector clean up those objects.

Ray Hayes points out that the .NET garbage collector will not immediately collect the out-of-scope objects, so scoping is the main benefit.

Ed Schwehm
Have you actually verified this at the VM level? Most reasonable compilers and GCs will tend to collapse the two blocks into one during the compilation process, and can GC a value after the last use of the variable that refers to it.
emk
I have not verified the garbage collection, but I have verified the scope. I'm pretty sure the .NET garbage collector will collect things that have left scope/are not referenced.
Ed Schwehm
The GC could kick in, but it may not for a while! Loss of scope does not mean automatic GC. Also, in this case, for value types there would have been nothing to GC. Scoping is the main purpose here, not GC.
Ray Hayes
Good point, Ray. I'll edit my answer.
Ed Schwehm
A: 

One reason for doing this is that the variables 'z' and 'zz' would not be available to code below the end of that inner block. When you do this in Java, the JVM pushes a stack frame for the inner code, and those values can live on the stack. When the code exits the block, the stack frame is popped and those values go away. Depending on the types involved, this can save you from having to use heap and/or garbage collection.

nsayer
+2  A: 

It's a by-product of a the parser rule that statement is either a simple statement or a block. i.e. a block can be used wherever a single statement can.

e.g.

if (someCondition)
 SimpleStatement();

if (SomeCondition)
{
   BlockOfStatements();
}

Others have pointed out that variable declarations are in scope until the end of the containing block. It's good for temporary vars to have a short scope, but I've never had to use a block on it's own to limit the scope of a variable. Sometimes you use a block underneath a "using" statement for that.

So generally it's not valuable.

Anthony
A: 

In C# -- like c/c++/java -- braces denote a scope. This dictates the lifetime of a variable. As the closing brace is reached, the variable becomes immediately available for a garbage collection. In c++, it would cause a class's destructor to be called if the var represented an instance.

As for usage, the only possible use is to free up a large object but tbh, setting it to null would have the same effect. I suspect the former usage is probably just to keep c++ programmers moving to managed code somewhat in familiar and comfortable territory. If really want to call a "destructor" in c#, you typically implement the IDisposable interface and use the "using (var) {...}" pattern.

Oisin

x0n
A: 

Even if it was actually useful for any reason (e.g. variable scope control), I would discourage you from such construct from the standpoint of good old code readibility.

petr k.
A: 

There is no value to this other than semantic and for scope and garbage collection, none of which is significant in this limited example. If you think it makes the code clearer, for yourself and/or others, then you certainly could use it. However, the more accepted convention for semantic clarification in code generally would use line breaks only with option in-line comments:

public void TestMethod()
{
    //do something with some strings
    string x = "test";
    string y = x;

    //do something else with some ints
    int z = 42;
    int zz = z;
}
Tim Erickson
+3  A: 

An example would be if you wanted to reuse a variable name, normally you can't reuse variable names This is not valid

        int a = 10;
        Console.WriteLine(a);

        int a = 20;
        Console.WriteLine(a);

but this is:

    {
        int a = 10;
        Console.WriteLine(a);
    }
    {
        int a = 20;
        Console.WriteLine(a);
    }

The only thing I can think of right now, is for example if you were processing some large object, and you extracted some information out of it, and after that you were going to perform a bunch of operations, you could put the large object processing in a block, so that it goes out of scope, then continue with the other operations

    {
        //Process a large object and extract some data
    }
    //large object is out of scope here and will be garbage collected, 
    //you can now perform other operations with the extracted data that can take a long time, 
    //without holding the large object in memory

    //do processing with extracted data
BlackTigerX
A: 

This allows you to create a scope block anywhere. It's not that useful on it's own, but can make logic simpler:

switch( value )
{
    case const1: 
        int i = GetValueSomeHow();
        //do something
        return i.ToString();

    case const2:
        int i = GetADifferentValue();
        //this will throw an exception - i is already declared
 ...

In C# we can use a scope block so that items declared under each case are only in scope in that case:

switch( value )
{
    case const1: 
    {
        int i = GetValueSomeHow();
        //do something
        return i.ToString();
    }

    case const2:
    {
        int i = GetADifferentValue();
        //no exception now
        return SomeFunctionOfInt( i );
    }
 ...

This can also work for gotos and labels, not that you often use them in C#.

Keith