Quiz: Initializing static fields correctly


A dev on the team recently found a bug in Whidbey a long these lines…  Say you want to initialize the value of a static int to zero… which code should you use (C1 or C2) and, of course the most important point, why?

 

    class C1

    {

        private static int value = 0;

    }

 

    class C2

    {

        private static int value;

    }

 

 

BTW – I know these are not as tricky as some of my past ones… stay tuned, they will get harder 😉

Comments (20)

  1. I would use C1 because it’s explicit. C1 guarantees value to be initialized to 0. With C2 you’re left up to whatever the runtime assigns as the default.

  2. Matthew says:

    I am pretty sure C1 would also need a (blank) static constructor – otherwise there is no guarantee that 0 will be set:

    <quote>

    beforeFieldInit specifies that calling static methods of the type does not force the

    system to initialize the type

    </quote>

    Adding a static constructor solves the problem (from what I have read).

  3. Hmmm… empty static constructor… hadn’t thought of that…

  4. foobar says:

    C2 should be more efficient (no class constructor), but both should result in 0s

  5. dhananjay singh says:

    C2 is right chioce

    It will initiate to default value i.e. zero

  6. Wesner Moise says:

    C2 is concise means of initializing to zero and exhibits no risk of errors, whereas C1 effectively initializes the static variable twice. C1 runs the risk of initializing the static variable to zero after it has already been modified.

    C1 causes a static constructor to be generated. It automatically introduces a performance penalty whenever the static variable is accessed from outside a instance method in NGEN’ed code.

    C1 also creates the risk of a static variable being initialized after having been modified. There are a few instances where this can happen.

    If any static variable initializer contains a call to a static method, then that static method may modify other static variables, later in the code, prior to being initialized.

    The runtime alsos case, such as XML deserialization, where an object can be created and modified without being constructed; as a result, the static constructor may not be called before use and an instance method can the modify the value of static variable through an instance method before it is initialized. When a new object is subsequently initialized or a static variable is accessed, then the modified static variable will be erroneously initialized back to zero.

    I have experienced cases where the static constructor was not called because of my use of reflection.

  7. Irving Reid says:

    Wow, that’s really disturbing. Explicit initialization of static data elements, as shown in C1, is a *required* programming technique in many languages (such as C and C++), and is considered "best practice" in many others.

    Now, programmers who have trained for years to always explicitly initialize their variables are going to end up with subtly broken software, in a way that is brutally difficult to debug. This sure smells like a serious bug in the runtime environment to me.

  8. Jeff Lewis says:

    Both should work, but C2 is more performant.

    It actually does make a difference in speed. We have an app with almost 1 million lines of C# (and another million of C++) that when we went through and removed these unneeded initializations, gained a significant amount of performance.

  9. As long as the runtime doesn’t change the way it assigns values (you said there was a bug, so I was thinking maybe its a bug in the way or what value is assigned by default to a primitive type such as Int32), C2 is the better choice, as no constructor is needed. C1 needs a constructor, but at least you are guaranteed to know the value of C1 when it gets initialized.

  10. JD says:

    What about access to those types from multiple threads? If both thread access C1 simultaneously, what is the guarantee that the value will be initialized only once?

    I would use C2 as 0 will be the default value anyway.

  11. mihailik says:

    If we talk about perfomance and implementation details, we may prefer to C2.

    But there is more important thing, readability. In terms of readability and clarity C1 is best choise. Semanticaly C1 exactly state: "value always must be initialized to zero, take no defaults in mind".

    So summaried: if you need any care about what value must be set, use field initializer. Even in other cases use field initializer unless you have more especial ideas.

  12. I read the comments here after arriving to the conclusion most people here have arrived to, but then I thought about something a bit more disturbing.

    Take the following code:

    class C3

    {

    _ _ private static int value = default(int);

    }

    This generates THE EXACT SAME CODE AS C1!

    I can accept the case in C1 generating the extra code, since it is using an explicit value (0), but it is specified that value types are automatically initialized to their default value. The code in C3 repeats that same thing, while there is zero value for it!

    I believe the code for C3 requires at least a warning and some optimization by the compiler.

    Another thing I wanted to note is that this case exists for the following case:

    class C4

    {

    _ _ private static object o;

    }

    class C5

    {

    _ _ private static object o = null;

    }

    class C6

    {

    _ _ private static object o = default(object);

    }

    Which means that the same behaviour exists for reference types.

    Don’t these deserve attention as well?

  13. Brad Williams says:

    Agree with mihailik. Though it is interesting that performance is noticeably reduced by explicit initialization, as Jeff found.

    If there’s a "bug" that an explicit initialization will happen after certain code has already updated the member, then that certain code is the problem. Unless we want to pretend that it’s not human beings maintaining code.

  14. Bart says:

    Isn’t value a reserved keyword in C#, thus neither of the snippets will work?

  15. No, value is a keyword, not a reserved word, which means it has special significance in certain contexts, but can still be used as an identifier.

  16. Amit Bahree says:

    So, I understand there are pros and cons for both – reliability vs. perf., but going back to the question at hand, what is the bug? I have used both styles and mostly they had been dependend on the coding guidelines of clients (I work for a SI).

  17. I would expect both of them to operate the same. I’ve looked at articles on BeforeFieldInit, and from what I can tell, there is no circumstance at all in which a static field can be accessed before the type is initialized. If Whidbey allows code to access the static field on the class before the static field is initialized, that definitely seems like a bug, or at least a deviation from the specification.

    It’s good to know that explicit initialization is less efficient than simple declaration. Is that the same case for instance members as well as class members?

  18. WPoust says:

    The actual IL generated which shows that C1 initializes the value to 0 along with generating a static constructor for the class. I would surmise that it gets initialized because the static member variable is referenced during the static member declaration which also triggers the creation of the static constructor (C# spec section:10.11).

    With C2 that’s not the case so the CLR waits until a class instance is constructed before initializing the all class members via a "set all members using default constructor" language feature (C# spec section:5.2).

    In certain cases, C2 will generate a compiler warning CS0649 because the variable is used before being initialized. Of course, no one would attempt say code is correct if it compiles. Nah… I’ve never heard that one before.

  19. Anon says:

    Interestingly, I tried the above code in both C# and VB.NET (in .NET 1.0) and they compile into different IL.

    In particular:

    public class C2

    {private static int Bob;}

    compiles to:

    .class public auto ansi beforefieldinit C2

    extends [mscorlib]System.Object

    {

    } // end of class C2

    and

    Public Class Class2

    Private Shared Bob As Integer

    End Class

    compiles to:

    .class public auto ansi Class2

    extends [mscorlib]System.Object

    {

    } // end of class Class2

    Can anyone explain the difference?