Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When do you use scope without a statement in C#?

Tags:

syntax

c#

block

Just recently I found out you can do this in C#:

{     // google     string url = "#";      if ( value > 5 )         url = "http://google.com";      menu.Add( new MenuItem(url) ); } {     // cheese     string url = "#"; // url has to be redefined again,                        // so it can't accidently leak into the new menu item      if ( value > 45 )         url = "http://cheese.com";      menu.Add( new MenuItem(url) ); } 

instead of i.e.:

    string url = "#";      // google     if ( value > 5 )         url = "http://google.com";      menu.Add( new MenuItem(url) );       // cheese     url = "#"; // now I need to remember to reset the url      if ( value > 45 )         url = "http://cheese.com";      menu.Add( new MenuItem(url) ); 

This might be a bad example that can be solved in a lot of other manners.

Are there any patterns where the 'scope without statement' feature is a good practice?

like image 658
Dirk Boer Avatar asked Dec 13 '14 11:12

Dirk Boer


People also ask

What are scope rules in C?

A scope in any programming is a region of the program where a defined variable can have its existence and beyond that variable it cannot be accessed. There are three places where variables can be declared in C programming language − Inside a function or a block which is called local variables.

How many types of scopes are there in C?

C has four kinds of scopes: block scope. file scope. function scope.

Why scope should be used for variable?

One of the basic reasons for scoping is to keep variables distinct from each other in multiple parts of the program. For example the programmers can use same variables for all loops such i and j, this can lead collision of variables hence the scope of the variable is necessary to avoid collisions and for more security.

How does a compiler implement scope rules?

Whenever a scope is introduced, the compiler gives it a name and puts it in a structure (a tree) that makes it easy to determine the position of that scope in relation to other scopes, and it is marked as being the current scope. When a variable is declared, its assigned to the current scope.


1 Answers

One use that I find acceptable in many cases, is to enclose each switch section of a switch statement in a local scope.


Late addition:

The local scope blocks { ... } present in the C# source do not seem to be relevant for the resulting IL bytecode. I tried this simple example:

static void A() {     {         var o = new object();         Console.WriteLine(o);     }      var p = new object();     Console.WriteLine(p); }  static void B() {     var o = new object();     Console.WriteLine(o);      var p = new object();     Console.WriteLine(p); }   static void C() {     {         var o = new object();         Console.WriteLine(o);     }      {         var o = new object();         Console.WriteLine(o);     } } 

This was compiled in Release mode (optimizations enabled). The resulting IL according to IL DASM is:

.method private hidebysig static void  A() cil managed {   // Code size       25 (0x19)   .maxstack  1   .locals init ([0] object o,            [1] object p)   IL_0000:  newobj     instance void [mscorlib]System.Object::.ctor()   IL_0005:  stloc.0   IL_0006:  ldloc.0   IL_0007:  call       void [mscorlib]System.Console::WriteLine(object)   IL_000c:  newobj     instance void [mscorlib]System.Object::.ctor()   IL_0011:  stloc.1   IL_0012:  ldloc.1   IL_0013:  call       void [mscorlib]System.Console::WriteLine(object)   IL_0018:  ret } // end of method LocalScopeExamples::A 

 

.method private hidebysig static void  B() cil managed {   // Code size       25 (0x19)   .maxstack  1   .locals init ([0] object o,            [1] object p)   IL_0000:  newobj     instance void [mscorlib]System.Object::.ctor()   IL_0005:  stloc.0   IL_0006:  ldloc.0   IL_0007:  call       void [mscorlib]System.Console::WriteLine(object)   IL_000c:  newobj     instance void [mscorlib]System.Object::.ctor()   IL_0011:  stloc.1   IL_0012:  ldloc.1   IL_0013:  call       void [mscorlib]System.Console::WriteLine(object)   IL_0018:  ret } // end of method LocalScopeExamples::B 

 

.method private hidebysig static void  C() cil managed {   // Code size       25 (0x19)   .maxstack  1   .locals init ([0] object o,            [1] object V_1)   IL_0000:  newobj     instance void [mscorlib]System.Object::.ctor()   IL_0005:  stloc.0   IL_0006:  ldloc.0   IL_0007:  call       void [mscorlib]System.Console::WriteLine(object)   IL_000c:  newobj     instance void [mscorlib]System.Object::.ctor()   IL_0011:  stloc.1   IL_0012:  ldloc.1   IL_0013:  call       void [mscorlib]System.Console::WriteLine(object)   IL_0018:  ret } // end of method LocalScopeExamples::C 

Conclusions:

  • Local scope declarations do not exist in any form in the IL bytecode.
  • The C# compiler will choose new names for local variables that would otherwise be in conflict (the second of the variables o in the C method).
  • People who feel (see other answers and comments to question) that the garbage collector might be able to do its work earlier when they introduce local scope in the C# source, are wrong.

I also tried compiling this in Debug mode (no optimizations). The start and end of a local scope seem to show up as a nop instruction only ("No operation"). In some cases two identically named local variables from distinct local scopes were mapped to the same local variable in the IL, like with C# method named C above. Such a "unification" of two variables is only possible if their types are compatible.

like image 111
Jeppe Stig Nielsen Avatar answered Sep 20 '22 14:09

Jeppe Stig Nielsen