Mucking around with instance field initializers – Part 1

What do you think of the following piece of code?


    class Program
{
int x = 1;
int y = x + 1;
}

Looks simple, except that it doesn’t compile (error CS0236: A field initializer cannot reference the non-static field, method, or property ‘Program.x’)

Try making x and y static – the code will compile fine now. I have been trying to find out why – so far, I haven’t got a clue. Just in case it’s not obvious, I do know that moving y = x + 1 into the body of Program’s constructor will get me what I want, but I was (and am) curious to know why field initializers, and only instance field initializers, aren’t allowed to access non-static fields.

The C# spec says that field initializers “correspond to a sequence of assignments that are executed immediately upon entry to any one of the instance constructors”, just before the call to the base class constructor. When I generated IL for Program’s constructor after replacing y = x + 1 with y = 2, it looked like this


    L_0000: ldarg.0 
L_0001: ldc.i4.1
L_0002: stfld int32 ConsoleApplication1.Program::x
L_0007: ldarg.0
L_0008: ldc.i4.2
L_0009: stfld int32 ConsoleApplication1.Program::y
L_000e: ldarg.0
L_000f: call instance void [mscorlib]System.Object::.ctor()
L_0014: nop
L_0015: ret


The generated IL matches with the spec – 1 and 2 are stfld’ed into x and y before calling the base class constructor (System.Object::.ctor()).

The C# spec also says that a field initializer is not allowed to reference the this pointer – “ variable initializer for an instance field cannot reference the instance being created.” It doesn’t say why though.

The IL shown above clearly indicates that this (ldarg.0) is valid when storing 1 and 2 into x and y. So why doesn’t C# allow y = x + 1?

I initially wondered if that rule is to prevent code like this 


    class Program
{
int x = y + 1;
int y = x + 1;
}

but then, the C# spec clearly says that the variable initializers will be run in “textual” order. If you combine that with the fact that x and y will be assigned their default values even before their variable initializers run, you’ll see that the above code should run fine, resulting in x = 1 (because y is zero) and y = 2. You can make x and y static and run the code, you will see the same result.

So again, why? Can you figure out why? We’ll do some more digging into this in the next post. 

One thought on “Mucking around with instance field initializers – Part 1”

  1. Hi anna,
    From your post :
    The IL shown above clearly indicates that this (ldarg.0) is valid when storing 1 and 2 into x and y.

    I got struck with the following question in mind……
    “this” is valid only after the Object .ctor() is called correct. So whether “this” is really valid at that point. I am thinking of x and y as seperate place holders at that point…. (sweat)

Leave a Reply

Your email address will not be published. Required fields are marked *


*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>