Why in C# does order matter for static initialization?
Asked Answered
A

4

8

This code has the well defined behavior in C# of not working:

class Foo
{
    static List<int> to = new List<int>( from ); // from is still null
    static IEnumerable<int> from = Something();
}

Note: I'm not asking how to fix that code as I already known how to do that

What is the justification for this? C# already does run time checks to detect the first access to static members. Why not extend this to a per member thing and have them run on demand or even better have the compiler figure out the order at compile time?

BTW: I think the same question (or almost the same) also holds for non static members.

Anaphrodisiac answered 18/3, 2009 at 21:29 Comment(1)
I think you answering yourself by saying this is 'well defined behavior'.Butterscotch
B
6

I can envision a programmer depending on initialization order due to side effects with other static classes. You and I both know that depending on side effects is bad practice, but it's not necessarily illegal.

Consider something like this:

class Foo
{
    static string header = Bar.GetHeader();
    static string version = Bar.GetVersion();
}

And Bar.GetVersion assumes that Bar.GetHeader has been called. If the compiler were free to change the initialization order, then the programmer wouldn't be able to guarantee the initialization order.

Ugly, granted, but perfectly legal. If you imagine second-order effects (i.e. called static methods that themselves depend on classes that have side effects), you see that it's impossible for the compiler to reliably rearrange anything, just as it's impossible (in general) for the compiler to rearrange the order of function calls in your static constructor.

Bioscope answered 19/3, 2009 at 0:23 Comment(1)
A good point and it might be the reason. That said I think that the "evaluate in order" way is wrong the way to solve that. I think the correct tact is to say, "if order matters, initialize in a constructor." and "Code that depends on order of inline initialization is illegal, even if it runs".Anaphrodisiac
A
13

Initializers are just a syntactic sugar. Compiler puts that code in the .cctor when it compiles your class, and it pust them in the orders they're layed out in the code.

It doesn't run any checks, because it wouldn't make sense. You could still have initialization cycles, so it wouldn't work anyway.

I blogged about it some time ago if you're interested:

Audiogenic answered 18/3, 2009 at 21:43 Comment(3)
That's the primary reason: initialization cycles that the compiler can't resolve.Bioscope
Cycles are always an error: I'd rather get compiler errors than what you currently get. Aside from cycles, I see no issues. +1Anaphrodisiac
>"Compiler puts that code in the .cctor." Surely this can't be right. Initializers are invoked in different order than constructors, right?Butterscotch
B
6

I can envision a programmer depending on initialization order due to side effects with other static classes. You and I both know that depending on side effects is bad practice, but it's not necessarily illegal.

Consider something like this:

class Foo
{
    static string header = Bar.GetHeader();
    static string version = Bar.GetVersion();
}

And Bar.GetVersion assumes that Bar.GetHeader has been called. If the compiler were free to change the initialization order, then the programmer wouldn't be able to guarantee the initialization order.

Ugly, granted, but perfectly legal. If you imagine second-order effects (i.e. called static methods that themselves depend on classes that have side effects), you see that it's impossible for the compiler to reliably rearrange anything, just as it's impossible (in general) for the compiler to rearrange the order of function calls in your static constructor.

Bioscope answered 19/3, 2009 at 0:23 Comment(1)
A good point and it might be the reason. That said I think that the "evaluate in order" way is wrong the way to solve that. I think the correct tact is to say, "if order matters, initialize in a constructor." and "Code that depends on order of inline initialization is illegal, even if it runs".Anaphrodisiac
S
1

I think what you need to use is a static constructor.

Like so

class Foo
{
    static List<int> to;
    static IEnumerable<int> from;

    static Foo()
    {
        from = Something();
        to = new List<int>(from);
    }
}

As to why C# doesn't do it on first access, I just don't see the need for that kind of complexity when there are other alternatives that make it clear what's happening.

Stricklan answered 18/3, 2009 at 21:33 Comment(7)
I read the question. Asking why C# does something one way, is never going to get you much of a useful answer. My reply was along the lines of, why would it when you can do this...Stricklan
Asking why something works in C# has worked a lot of times; just look at how much Jon Skeet knows about the mechanics of C#.Medici
It's better to use initialisation methods, FXCop will tell you this.Stroh
Regardless of what FXCop tells you, this does not answer the question.Medici
Yes but what's the point? It's not going to change. Also I had an answer to why before your down vote, and the other answer doesn't say why either.Stricklan
I know exactly how to fix the problem. I am looking for exactly what I asked for.Anaphrodisiac
@AdamRalph: My FXCop does not tell me this... @Ray: Static constructors do not have access modifiers because they are runned anyway.Airlift
G
1

C# does runtime checks to detect the first access to a class, but does not re-order static initialization within a class.

The static fields are initialized from top to bottom followed by the static constructors from top to bottom. Either change the order of your fields or create a static constructor and initialize the fields from tehre.

See Variable initializers in the C# spec or this article on initializers.. Also, the question Order of static constructors/initializers in C# is related.

Gruelling answered 18/3, 2009 at 21:34 Comment(3)
I asked that question :b Also see my comment to Ray. I'm /not/ asking how to fix that code.Anaphrodisiac
Yeah, you did. :-) I guess I should pay more attention!Gruelling
"'Something is wrong, please contact the sys admin', Crud! I would but I /am/ the sys admin!" <g/>Anaphrodisiac

© 2022 - 2024 — McMap. All rights reserved.