Friday, 19 November 2010

Using static in .Net

How often do you use the static keyword? Do you disagree with it from a puritan viewpoint that it demonstrates the hiding of functionality that belongs in a separate class? Do you even know what it means?
A static item essentially means there is only one copy. In C#, a static class cannot be instantiated (like a Singleton) and can only contain static members. A normal class can have static members (methods or fields) but these cannot be called on instances of the class, only on the class itself.
As with many things in life, static can be used well and it can be misused. However, I want to suggest that its use, if correct, is both good for performance and is also good for reliability! How do I know? Well look at the following code:

public class Car
{
private static int carCount = 0;
public static Car BuildCar()
{
++carCount;
// build car and return it
}
}

This is an example of lazy or misinformed programming. Why? Because why should a car 'know' about the number of cars that have been built? In reality, you should probably create a factory class that looks like the above and then it wouldn't have to be static right?

public class Car
{
// etc
}

public class CarFactory
{
private int carCount = 0;
public Car BuildCar()
{
++carCount;
// build car and return it
}
}

We could then keep a single instance of this class somewhere and access it to make our cars. This is OK but it misses a trick when it comes to performance. In simple systems, to be fair, it is unlikely to be noticeable but in the above example, although we are only intending for there to be 1 CarFactory instance, the compiler doesn't know this and therefore every call to one of the instance methods has to resolve which instance (i.e. which block of memory) is being accessed. By using static, we tell the compiler that we only want one 'instance' and therefore the class is loaded when the assembly/program is loaded and is instantly available - bit like a direct pointer to methods/fields. This is good!
The same basic truth also concerns methods on classes that can be static i.e. any methods that do not access instance variables in the class. So although they do not have to be static, by making them so, we avoid the resolution of instance. Look at the following:

public class CarFactory
{
public void PaintCar(ref Car car, Color colour)
{
car.Colour = colour;
}
}

The method does not have to be marked static but in this case, it only operates on the values passed into the method and therefore should be marked static for performance reasons. Since, like all good programmers, we never modify methods after they are released, we would never need to change it to non-static, we would simply add another non-static method to do the work differently! In some cases, classes have static methods that operate on passed in values and instance methods that do the same thing on the instance itself:

public class Car
{
public static void PaintCar(ref Car car, Color colour)
{
car.Colour = colour;
}
public void PaintCar(Color colour)
{
this.Colour = colour;
}
}

The second and not to be ignored benefit of using static is that the compiler will enforce the fact that a static method is not allowed to access instance fields and that a static class cannot be instantiated. Why is this important? Because this improves reliability. Take the code snippet above. If our Car class had 20 member fields (instance, not static) and we wanted to test the two functions above, how many combinations would we need to test? In reality, we might look at a function and see that it doesn't access member fields but what if it called other methods which called other methods? Ideally we would need to consider every possible combination of instance fields as well as the parameters passed in. For the static method? We know that we cannot accidentally read or write any instance fields so we simply test for all valid permutations of the input (we might test in our case for a null Car, a null Color, a valid Car and a valid Color to ensure our code is robust).
Of course we always ignore reliability because we think we are good engineers and won't make stupid mistakes. To be perfectly honest, we make plenty and need as much help as we can to avoid them. That's why you should use static wherever possible!
Post a Comment