Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Interesting feature with static fields. StackOverflow exception

Tags:

oop

Do you have any idea, why the following code:

public class A
{
    public static int i = B.i + 1;
}

public class B 
{
    public static int i = A.i + 1;
}

Having:

        int aa = A.i;
        int bb = B.i;

Says that aa = 2 (!!!) and bb = 1.

I have a STACK OVERFLOW in my brain!!! As far as i understand, recursion stops on static methods, but why? If you remake int i to the getters (to debug and understand why on earth it works like that), you get the stack overflow exception.

like image 641
0100110010101 Avatar asked Apr 21 '26 18:04

0100110010101


2 Answers

No doubt execution is happening like so:

The B.i static initializer runs first, and sets B.i = A.i + 1. Since A.i hasn't been initialized yet, A.i is equal to default(int), which is 0. B.i gets the value 1.

The A.i static initializer runs second, and sets A.i = B.i + 1 = 2.

Since static initializers run in an undefined order, you might find that a different field is 2 each time when you run it, or that they switch when you make other structural changes to your code. However, one should always wind up as 2, and one should always be 1.

P.S. This has nothing to do with polymorphism.

EDIT: For some further understanding of the timing of static initializers and constructors, you might want to examine this relevant portion of the C# specification.

like image 150
mqp Avatar answered Apr 24 '26 12:04

mqp


A field is not like a property getter. It just stores the data, not any operation. In fact, the initialization will be moved to another method (static constructor, .cctor) which will initialize static variables in the class.

At the beginning, both will equal to 0. Before you access A.i for the first time, the method .cctor for class A runs. It tries to access B.i for the first time which will cause execution of the static constructor of class B. .cctor of B will try to access A.i but since it's not the first time a field is being accessed, static constructor of A will not run anymore. It just fetches the current value of A which is still 0. Consequently, B.i will be equal to 1 when B..cctor finishes execution and control is returned to A..cctor. It will see the value B.i and adds 1 to it and stores it in A.i. Thus, A.i will be equal to 2 (1+1) and B.i will be equal to 1.

The only guarantee you get is that the static constructor will be called before any static member of that class is accessed.

like image 38
mmx Avatar answered Apr 24 '26 13:04

mmx