VB.NET Variable Auto-Intializaton and the CLR

Mike_R

Junior Contributor
Joined
Oct 20, 2003
Messages
316
Location
NYC
I was thinking about how VB.NET auto-initializes its variables if not explicitly written to before being read, something that C# does not allow. The simplest example would be something like this:

Code:
' VB.NET:
Public Sub MySub()
    Dim j As Integer
    MessageBox.Show(j.ToString)
End Sub

The equivalent in C# would not compile:

Code:
// C#:
public void MySub()
{
    int j;
    MessageBox.Show(j.ToString());
}
The compiler would complain about "Use of unassigned local variable 'j'" at the point where 'j.ToString()' is called.

So I wondered what the VB.NET code would look like when viewing the IL. I had expected to find an explicit assignment of 'j' to 0, presumably created by the VB.NET compiler. But I was surprised at what I found:

Code:
.method public instance void MySub() cil managed
{
    .maxstack 1
    .locals init (
        [0] int32 j)
    L_0000: ldloca.s j
    L_0002: call instance string [mscorlib]System.Int32::ToString()
    L_0007: call valuetype [System.Windows.Forms]System.Windows.Forms
                .DialogResult [System.Windows.Forms]System.Windows.Forms
                .MessageBox::Show(string)
    L_000c: pop 
    L_000d: ret 
}

Basically, the 'int32 j' is not assigned a value before .ToString() is called. I had expected to see 'j' being set to zero via a 'ldc.i4.0' call followed by 'stloc.0' and then the rest of the routine would proceed as shown above.

That is, I had expected to see this:
Code:
.method public instance void MySub() cil managed
{
    .maxstack 1
    .locals init (
        [0] int32 j)
    L_0000: ldc.i4.0 
    L_0001: stloc.0 
    L_0002: ldloca.s j
    L_0003: call instance string [mscorlib]System.Int32::ToString()
    L_0004: call valuetype [System.Windows.Forms]System.Windows.Forms
                .DialogResult [System.Windows.Forms]System.Windows.Forms
                .MessageBox::Show(string)
    L_0005: pop 
    L_0006: ret 
}
So does the CLR itself zero out all variables? And therefore VB.NET is not really "doing anything", but instead is merely allowing the default behavior to occur, whereas C# is being more restrictive?

Or is there a CIL setting, attribute, or the like somewhere that determines whether unassigned memory should be zeroed out before use automatically? (A setting that VB.NET would be using, but not C#?)

Anyway, I was wondering if anyone here knew what was going on...

Mike
 
The actual initalisation is done in the
Code:
  .locals init (
        [0] int32 j)
bit.

The runtime appears to always initialise variables, c# requires an explicit assignment before use though...

In fact if you change the c# version to be int j = 0; then you get exactly what you expected.
 
Ok, thanks PD for clearing that up. :-)

Funny, I had thought it was the other way around: that the CLR would not be taking extra steps like this and that VB.NET was "injecting code" to zero it out.

Funny, then, that C# does not enforce field initializers? It would seem much easier to enforce that a field is initialized at the point of declaration (or within all constructors) than the complex path analysis that C# must undergo for variables? C# seems to be saying that it's ok to assume that a field will be the default null/0/false but it's not ok to assume the same for a variable?

Anyway, thanks for solving this mystery for me, PD. One less thing keeping me up at night... :)
 
Back
Top