AddThis Social Bookmark Button

Print

Static Constructors Demystified
Pages: 1, 2

Static Constructor Presence Trumps beforeFieldInit

Interestingly enough, according to the rules resource, r2 gets initialized first, before the static constructor is called and r1 is initialized. Even if r2 is never needed, it will still be initialized first. Defining a static constructor seems to "trump" the beforeFieldInit. So even if you have an empty static constructor, it is guaranteed that static variables will be initialized before any static function gets invoked.



If there is no static constructor, then the following rule taken from the C# documentation applies to the initialization of static variables:

"The static field variable initializers of a class correspond to a sequence of assignments that are executed at an implementation-dependent time prior to the static constructor for the class (if any) and prior to the first use of a static field of that class. The static field variable initializers are executed in the textual order in which they appear in the class declaration."

Summarizing the Usage of Static Constructors

It is one thing to open an Oxford English Language dictionary and learn a new word, and completely another thing before the word becomes part of the usage on a daily basis. Programming constructs are no different. These constructs need to be internalized before one can effectively use them. This is how I intend to internalize the static constructors:
  • A static constructor looks like a default constructor with static in front.
  • It is an error to attach public/private/or protected to a static constructor.
  • The presence of a static constructor suppresses beforeFieldInit.
  • Static field variables are initialized before the static constructor is called.
  • Having a static constructor is the only way to ensure that all resources are initialized before other static functions are called.

When Is It OK Not to Use Static Constructors?

If all of your static variables can be set up by simply instantiating classes against them, then there is a good chance that you don't need a static constructor. What you have to watch out for, though, is that none of the constructors of these classes have side effects; for example, a class1 constructor doing something useful for a class2 constructor, or the usage of a class2 instance. In such a case, if a class2 variable is to be utilized first, then there is no guarantee that a class1 constructor would have run. Surprisingly, even this won't be a problem if these instances are the static instances of the same class; as soon as one of the class instances is utilized, everything in that class is initialized.

When to Use Static Constructors

If a class has a set of static variables that are mainly simple types and not functional classes, then these simple types need to be initialized procedurally, as opposed to instantiating them. For example, I consider ints, strings, etc., as simple types (although they are classes in their own right). A logging class needs to remember its log filename, log message levels etc., at start up. Assuming this log class is implemented as a static class, a static constructor will initialize these variables. If you want to do this using static variable initialization, then you need to have a class called LogInitialization, whose sole purpose is to initialize this static instance.

Singletons and Static Constructors


public class MySingletonClass
{
  public static MySingletonClass self = new MySingletonClass();
  //Nonstatic MySIngletonClass implementation follow
}

//singletonusage

MySingletonClass.self.doSomething();

The above example shows that the majority of singletons don't require static initializers.

An Alternative to Static Classes

There is no such language construct called a static class. I tend to refer to a class as a static class when much of its functionality is exposed as a collection of static functions. Often, these classes give rise to static constructors. It is possible to convert a static class to a regular class and use a singleton of this type, instead of the static class with which we have started. There are pros and cons to both approaches. First, let me show examples of both usages.

The Static Example Revisited



//Class definition

public class UtilityClass
{

  //Resources
  static Resource1 r1 = null;

  static void f1(){}
  static void f2(){}
}

//Let us see how the above class is used

UtilityClass.f1();
UtilityClass.f2();

In this scenario, programmers will directly call the static functions as if they are C-like functions. This approach has a lot of simplicity and as a result, is usually preferred for utility functions. On the negative side of this approach lies the first assertion that this is not object-oriented programming. If it gets the job done, and programmers use it without major drawbacks, this is quite reasonable.

Static Classes as Singletons

Let me rewrite the above class as a singleton and show how programmers can use such a facility.



//Class definition

public class SingletonUtilityClass
{
  public static SingletonUtilityClass self = new SingletonUtilityClass();

  //Resources
  Resource1 r1 = null;

  void f1(){}
  void f2(){}
}

//Let us see how the above class is used

SingletonUtilityClass.self.f1();
SingletonUtilityClass.self.f2();

Notice now that the class is a non-static, regular class. The only static variable is the "self" variable pointing to an instance of itself. This is a little bit more verbose than the static version of it. In addition to that you have to ensure the singleton semantics of it. You should ensure that the constructor of this is private and is not allowed to instantiate from anywhere, etc.

There is a reward for going this extra step. In the above example, the class is statically bound to the program. If you can utilize a factory that can dynamically instantiate classes and also permits the multiplicity of their instantiations, then you can take the above class and makes it a strategy/factory pattern. Once this happens, you can then change your implementation of methods at run time. When properly expanded, this method forms the basis of remoting, COM+, etc.

References

Satya Komatineni is the CTO at Indent, Inc. and the author of Aspire, an open source web development RAD tool for J2EE/XML.


Return to ONDotnet.com