views:

226

answers:

8

Should I instantiate my worker variables inside or outside my for loop

E.g.

a)

bool b = default(bool);

for (int i = 0; i < MyCollection.Length; i++)
{
  b = false;

  foreach(object myObject in myObjectCollection)
  {
    if (object.Property == MyCollection[i].Property)
    {
      b = true;
      break;
    }
  }      

  if (b)
  {
    DoSomethingWith(MyCollection[i]);
  }
}

b)

for (int i = 0; i < MyCollection.Length; i++)
{
  bool b = default(bool);

  foreach(object myObject in myObjectCollection)
  {
    if (object.Property == MyCollection[i].Property)
    {
      b = true;
      break;
    }
  }      

  if (b)
  {
    DoSomethingWith(MyCollection[i]);
  }
}

EDIT: Seems universally agreed that there will be no difference where the IL is concerned. But for readability and clarity of scope... inside is better

A: 

I like to declare them inside the loop, it saves a line of code (to declare and set it on the same line), and it's easier to see what variables I'm using outside and inside the scope of the loop, which is good when you're working on something complicated.

Marc Charbonneau
+1  A: 

inside looks cleaner but agree with Jon, the IL will be the same.

Russ Cam
+1  A: 

Previous answer deleted as I'd misread the code. (Using "default(bool)" anywhere is a bit odd, btw.)

However, unless the variable is captured by a delegate etc, I'd expect them to either compile to IL which is effectively the same (in terms of both behaviour and performance).

As ever, write the most readable code first. Micro-optimising things like this is asking for trouble. I agree with the others who have suggested that you restrict the scope of variables as much as you can - so if you need it after the loop, you haven't got any choice anyway; otherwise declare it inside.

Okay, here's a test program:

using System;

class Test
{
    static void Main() {}

    static void DeclareInside()
    {
        for (int i=0; i < 10; i++)
        {
            bool x = false;
            for (int j=5; j < 20; j++)
            {
                if (i == j)
                {
                    x = true;
                    break;
                }
                if (x)
                {
                    Console.WriteLine("Yes");
                }
            }
        }
    }

    static void DeclareOutside()
    {
        bool x;
        for (int i=0; i < 10; i++)
        {
            x = false;
            for (int j=5; j < 20; j++)
            {
                if (i == j)
                {
                    x = true;
                    break;
                }
                if (x)
                {
                    Console.WriteLine("Yes");
                }
            }
        }
    }
}

Generated IL (just csc Test.cs):

.method private hidebysig static void  DeclareOutside() cil managed
{
  // Code size       79 (0x4f)
  .maxstack  2
  .locals init (bool V_0,
           int32 V_1,
           int32 V_2,
           bool V_3)
  IL_0000:  nop
  IL_0001:  ldc.i4.0
  IL_0002:  stloc.1
  IL_0003:  br.s       IL_0045
  IL_0005:  nop
  IL_0006:  ldc.i4.0
  IL_0007:  stloc.0
  IL_0008:  ldc.i4.5
  IL_0009:  stloc.2
  IL_000a:  br.s       IL_0037
  IL_000c:  nop
  IL_000d:  ldloc.1
  IL_000e:  ldloc.2
  IL_000f:  ceq
  IL_0011:  ldc.i4.0
  IL_0012:  ceq
  IL_0014:  stloc.3
  IL_0015:  ldloc.3
  IL_0016:  brtrue.s   IL_001d
  IL_0018:  nop
  IL_0019:  ldc.i4.1
  IL_001a:  stloc.0
  IL_001b:  br.s       IL_0040
  IL_001d:  ldloc.0
  IL_001e:  ldc.i4.0
  IL_001f:  ceq
  IL_0021:  stloc.3
  IL_0022:  ldloc.3
  IL_0023:  brtrue.s   IL_0032
  IL_0025:  nop
  IL_0026:  ldstr      "Yes"
  IL_002b:  call       void [mscorlib]System.Console::WriteLine(string)
  IL_0030:  nop
  IL_0031:  nop
  IL_0032:  nop
  IL_0033:  ldloc.2
  IL_0034:  ldc.i4.1
  IL_0035:  add
  IL_0036:  stloc.2
  IL_0037:  ldloc.2
  IL_0038:  ldc.i4.s   20
  IL_003a:  clt
  IL_003c:  stloc.3
  IL_003d:  ldloc.3
  IL_003e:  brtrue.s   IL_000c
  IL_0040:  nop
  IL_0041:  ldloc.1
  IL_0042:  ldc.i4.1
  IL_0043:  add
  IL_0044:  stloc.1
  IL_0045:  ldloc.1
  IL_0046:  ldc.i4.s   10
  IL_0048:  clt
  IL_004a:  stloc.3
  IL_004b:  ldloc.3
  IL_004c:  brtrue.s   IL_0005
  IL_004e:  ret
} // end of method Test::DeclareOutside

.method private hidebysig static void  DeclareInside() cil managed
{
  // Code size       79 (0x4f)
  .maxstack  2
  .locals init (int32 V_0,
           bool V_1,
           int32 V_2,
           bool V_3)
  IL_0000:  nop
  IL_0001:  ldc.i4.0
  IL_0002:  stloc.0
  IL_0003:  br.s       IL_0045
  IL_0005:  nop
  IL_0006:  ldc.i4.0
  IL_0007:  stloc.1
  IL_0008:  ldc.i4.5
  IL_0009:  stloc.2
  IL_000a:  br.s       IL_0037
  IL_000c:  nop
  IL_000d:  ldloc.0
  IL_000e:  ldloc.2
  IL_000f:  ceq
  IL_0011:  ldc.i4.0
  IL_0012:  ceq
  IL_0014:  stloc.3
  IL_0015:  ldloc.3
  IL_0016:  brtrue.s   IL_001d
  IL_0018:  nop
  IL_0019:  ldc.i4.1
  IL_001a:  stloc.1
  IL_001b:  br.s       IL_0040
  IL_001d:  ldloc.1
  IL_001e:  ldc.i4.0
  IL_001f:  ceq
  IL_0021:  stloc.3
  IL_0022:  ldloc.3
  IL_0023:  brtrue.s   IL_0032
  IL_0025:  nop
  IL_0026:  ldstr      "Yes"
  IL_002b:  call       void [mscorlib]System.Console::WriteLine(string)
  IL_0030:  nop
  IL_0031:  nop
  IL_0032:  nop
  IL_0033:  ldloc.2
  IL_0034:  ldc.i4.1
  IL_0035:  add
  IL_0036:  stloc.2
  IL_0037:  ldloc.2
  IL_0038:  ldc.i4.s   20
  IL_003a:  clt
  IL_003c:  stloc.3
  IL_003d:  ldloc.3
  IL_003e:  brtrue.s   IL_000c
  IL_0040:  nop
  IL_0041:  ldloc.0
  IL_0042:  ldc.i4.1
  IL_0043:  add
  IL_0044:  stloc.0
  IL_0045:  ldloc.0
  IL_0046:  ldc.i4.s   10
  IL_0048:  clt
  IL_004a:  stloc.3
  IL_004b:  ldloc.3
  IL_004c:  brtrue.s   IL_0005
  IL_004e:  ret
} // end of method Test::DeclareInside

The only differences are where the variables are located within the stack.

Jon Skeet
Using = default(bool) just because I know its the same as saying = false (although now im doubting myself!)
Nick Allen - Tungle139
Yes, it's the same as saying "= false" - but at first glance that was the biggest difference I saw between the two code samples. Just inside the loop, you used "= false" for one and "= default(bool)" for the other.
Jon Skeet
+1  A: 

Inside. Variables should be scoped to their actual use. Declaring it outside scopes the variable to the containing block which is unnecessary and could possibly cause confusion.

EDIT: I'm guessing that this code is just to illustrate the example, but I'd actually omit the extraneous variable and write it as:

for (int i = 0; i < MyCollection.Length; i++)
{
   foreach(MyObjectClass myObject in myObjectCollection)
   {
        if (myObject.Property == MyCollection[i].Property)
        {
             DoSomethingWith(MyCollection[i]);
             break;
        }
   }
}
tvanfosson
A: 

Declare your variables as close as possible to the first place you use them and let the compiler worry about generating the most efficient IL (in this case at least).

Andrew Kennan
A: 

Another point is scope. If a variable is declared outside a loop, should I be expecting it to be used after the loop ? That is what I usually assume.

siz
A: 

Write your code with the reader as the first thing in your mind. A surprisingly small portion of code should be optimized.

There is often a tradeoff between optimization and readability. Since most of the manpower is spent revising and editing existing code, it is usually the right decision to lean toward readability over optimization.

The 80/20 rule is often applied here.

Jarred McCaffrey
A: 

I agree siz, i depends on the scope, If the variable is not to beused anywhere except inside the loop then declare it inside the loop. If it is to be used after the loop has finished then it need to be declared outside.

Blounty