Instance variable initializers - C# vs. VB.NET

I ran into an interesting issue today when changing some VB.NET code. I was surprised at the outcome so I did a quick repro case in C# and didn't have a problem.

Given this simple C# app, the results are pretty easy to predict:

using System;

namespace InheritIssue
{
	class Class1
	{
		[STAThread]
		static void Main(string[] args)
		{
			Foo f = new Foo();
		}
	}

	public class Base
	{
		private int _data;

		public Base()
		{
			Init();
		}

		protected virtual void Init()
		{
			_data = 1;
			Console.WriteLine("Data initialized to " + _data);
		}
	}

	public class Foo :  Base
	{
		private Alpha a = new Alpha();

		public Foo() : base()
		{
			Console.WriteLine("hello");
		}

		protected override void Init()
		{
			base.Init();
			Console.WriteLine("Initial Age: " + a.Age);
		}
	}

	public class Alpha
	{
		private int _age = -1;

		public int Age
		{
			get { return _age; }
			set { _age = value; }
		}
	}
}

In case you don't feel like running the code, you'll get:

Data initialized to 1
Initial Age: -1
hello

Now the same code in VB.NET:

Option Strict On
Option Explicit On

Namespace InheritIssue

    Public Class Class1

        <STAThread()> _
        Shared Sub Main()
            Dim f As Foo = New Foo
        End Sub


        Public Class Base
            Private _data As Integer

            Public Sub New()
                Init()
            End Sub

            Protected Overridable Sub Init()
                _data = 1
                Console.WriteLine("Data initialized to " & _data)
            End Sub
        End Class

        Public Class Foo
            Inherits Base

            Private a As Alpha = New Alpha

            Public Sub New()
                MyBase.New()
                Console.WriteLine("hello")
            End Sub

            Protected Overrides Sub Init()
                MyBase.Init()
                Console.WriteLine("Initial Age: " & a.Age)
            End Sub
        End Class

        Public Class Alpha
            Private _age As Integer = -1

            Public Property Age() As Integer
                Get
                    Return _age
                End Get
                Set(ByVal Value As Integer)
                    _age = Value
                End Set
            End Property
        End Class

    End Class

End Namespace

This code gets to the Base class initializer and outputs "Data initialized to 1". It then throws a NullReferenceException trying to access the Age property of the "a" object. The "a" variable has not been initialized and is still null (Nothing). I thought this was odd so I checked out the IL for Foo's constructor in both the C# and VB.NET version and saw something noticeably different.

In C#, the ctor is:

.method public hidebysig specialname rtspecialname 
        instance void  .ctor() cil managed
{
  // Code size       28 (0x1c)
  .maxstack  2
  IL_0000:  ldarg.0
  IL_0001:  newobj     instance void InheritIssue.Alpha::.ctor()
  IL_0006:  stfld      class InheritIssue.Alpha InheritIssue.Foo::a
  IL_000b:  ldarg.0
  IL_000c:  call       instance void InheritIssue.Base::.ctor()
  IL_0011:  ldstr      "hello"
  IL_0016:  call       void [mscorlib]System.Console::WriteLine(string)
  IL_001b:  ret
} // end of method Foo::.ctor

In VB.NET, there's an ever-so-slight difference:

.method public specialname rtspecialname 
        instance void  .ctor() cil managed
{
  // Code size       28 (0x1c)
  .maxstack  8
  IL_0000:  ldarg.0
  IL_0001:  call       instance void InheritIssue.Class1/Base::.ctor()
  IL_0006:  ldarg.0
  IL_0007:  newobj     instance void InheritIssue.Class1/Alpha::.ctor()
  IL_000c:  stfld      class InheritIssue.Class1/Alpha InheritIssue.Class1/Foo::a
  IL_0011:  ldstr      "hello"
  IL_0016:  call       void [mscorlib]System.Console::WriteLine(string)
  IL_001b:  ret
} // end of method Foo::.ctor

C# initialized the "a" variable to a new instance of Alpha before calling the base ctor. VB.NET did not do this. So when the Init method is called in Foo(), "a" is still null in the VB.NET version and you get a NullReferenceException. I checked the Visual Basic Language Specification for instance constructors and it states:

When a constructor's first statement is of the form MyBase.New(...), the constructor implicitly performs the initializations specified by the variable initializers of the instance variables declared in the type. This corresponds to a sequence of assignments that are executed immediately after invoking the direct base type constructor. Such ordering ensures that all base instance variables are initialized by their variable initializers before any statements that have access to the instance are executed.

Emphasis added by me. Now checking the C# spec:

When an instance constructor has no constructor initializer, or it has a constructor initializer of the form base(...), that constructor implicitly performs the initializations specified by the variable-initializers of the instance fields declared in its class. This corresponds to a sequence of assignments that are executed immediately upon entry to the constructor and before the implicit invocation of the direct base class constructor. The variable initializers are executed in the textual order in which they appear in the class declaration.

Whoa! Important difference there (very different!). I wonder why the language designers chose such a different path on deciding when to intialize instance variables?

Published Wednesday, February 22, 2006 10:18 PM by PSteele

Comments

# re: Instance variable initializers - C# vs. VB.NET

I ran into this ac ouple of years ago and was quite surprised to find out the way the 2 languages initialize are different. Made translating some code from one to the other a bit tricky. The oriignal code worked fine but the translated code failed. So after stepping through both I could see the issue. Your description is much better though.

Wednesday, February 22, 2006 11:19 PM by Joe

# re: Instance variable initializers - C# vs. VB.NET

You might be interested in checking this out:
http://www.panopticoncentral.net/archive/2006/02/13/11145.aspx

We're still awaiting a follow up from paul, but it highlights an interesting difference between C# and VB.NET

Thursday, February 23, 2006 7:02 AM by karl

# re: Instance variable initializers - C# vs. VB.NET

Sorry, only read this blog post now.

This problem has also caught me a few times in the past. I thought the general rule was not to call a virtual method from within a class.

Monday, March 13, 2006 2:04 PM by Kevin

# re: Instance variable initializers - C# vs. VB.NET

Good One Man keep it up

Thursday, March 16, 2006 2:05 AM by Ritesh Parikh

# VB.net Instance Variable Initializers vs the Constructor &mdash; Visual Basic Feng Shui

Pingback from  VB.net Instance Variable Initializers vs the Constructor &mdash; Visual Basic Feng Shui