views:

245

answers:

4

This works:

class MyClass
{
    int a;

    public MyClass()
    {
        int b = a;
    }
}

But this gives a compiler error ("Use of unassigned local variable 'a'"):

class MyClass
{
    public MyClass()
    {
        int a;
        int b = a;
    }
}

As far as I can tell this happens because in the first example, technically, the compiler doesn't know that 'a' is not assigned. In the latter example, 'a' is defined locally, and therefore is easy to track.

But why does the latter example not work?

Don't integers default to 0? Is this something the compiler enforces for "best practices". Or is there another reason?

+10  A: 

Don't integers default to 0?

They do when they're data members of a class, but not when they're a local variable: local variables need to be initialized explicitly before they're used, hence the compiler error.

ChrisW
http://msdn.microsoft.com/en-us/library/aa691170%28VS.71%29.aspx : "A local variable is not automatically initialized and thus has no default value. For the purpose of definite assignment checking, a local variable is considered initially unassigned."
+23  A: 

In the first example it is a field. Fields automatically default to 0/false/null. In the second example it is a variable. Variables are not defaulted, and must have "definite assignment" before they are used.

Essentially, when creating an object (or initializing a struct) it zeros the memory (or in the case of a non-default struct ctor, forces you to manually initialize everything). However, variables are so common (in every method) that it doesn't want the overhead of having to zero the stack all the time. It instead forces you to indicate the initial value.

Marc Gravell
The other option is to just not initializing the variable (and leave it the garbage that currently exist on the stack). But since C# sometimes goes beyond measures to get your code to be extra safe, the compiler insists that the variable would be initialized to some default value anyway (even if it's not required)
This also enables the compiler to optimize re-use of locals. eg: "for(...){ int j;... } for(...){ int k;... }" -- the compiler can re-use the space allocated for j when k comes along because they never overlap. If k has to be initialized before it is used then we never need to worry about leaving the former value of j in there.
Eric Lippert
Cheers Eric
Marc Gravell
That's all there is to it from C# point of view, but CLR begs to differ. If you want verifiable code (as C# produces by default), your local variables will have to be zero-initialized as well - fire up `ildasm` on your C# HelloWorld app and check for yourself! Of course, JIT can (and does) elide the initialization when it sees that variable is immediately assigned a different value, but that's another story (and one less level of abstraction down the ladder).
Pavel Minaev
+2  A: 

When you instantiate a new instance of a class all the memory that the object needs is "zeroed" ints are set to 0 strings are set to null etc. This is to avoid a lot of the weird memory bugs and hacks that were possible in C(++). Unfortunately this also has a small processing cost, so when you create a local variable the language assumes is that you will set the value yourself very soon and doesn't bother zeroing it to decrease the total number of required instructions. To offset the risk of using unset memory this introduces the compiler checks to ensure that a value has been set before it will allow you to use the variable.

Martin Harris
+2  A: 

That could be because variable declared at class level cannot be assigned value at the same scope (other than when declaring)

e.g

class Test
{
   int a;

   a = 0; // this is not allowed at class level & hence a initialized to default
}

whereas

class Test
{
   void test()
   {
     int a;
     int b = a;

     a = 20; // this is allowed
   }
}
shahkalpesh
@Marc: Yes. What I am trying to say is - At the class level, you cannot assign a value to the field on a separate line from that of declaration of it.
shahkalpesh
+1 for effort :)
SkippyFire