About Me

Hello, I'm an eclectic software professional working with enterprise software at SAP. This blog only contains my personal views, thoughts and opinions. It is not endorsed by SAP nor does it constitute any official communication of SAP.

Friday, September 18, 2009

C# Static Classes are not Real Classes

In C# and in Java, there's a common idiom to provide utility functions as static methods of classes that cannot be instantiated. This stems from the limitation that these languages don't allow the definition of any function outside of a class. This can be seen as an anti-pattern, because what's missing is the ability to declare functions, not only classes; like in C++.

The class has to be declared sealed (final in Java) and a private constructor must be created to prevent inadvertent instantiation.

public sealed class ConversionUtils {
  private ConversionUtils {}
  public static double ConvertTemperature(
    double fromTemperature, 
    TemperatureUnit fromUnit, 
    TemperatureUnit toUnit) { 
    ... 
  }
}

In C# 2.0, static classes were introduced to the language. A static class is a special type of class that's annotated with the static modifier and that:

  1. can't be instantiated (implicitly abstract)
  2. can't be subclassed (implicitly sealed)
  3. can't subclass other classes (only Object), nor implement interfaces
  4. must only contain static members (but you still have to use the redundant static keyword in each one, much like declaring your interface methods public and abstract - which is possible in Java!)
public static class ConversionUtils {
  public static double ConvertTemperature(
    double fromTemperature, 
    TemperatureUnit fromUnit, 
    TemperatureUnit toUnit) { 
    ... 
  }
}

That actually made things worse, because static classes promote the idiom that was being used to create stand-alone functions to the language level. Now the workaround is endorsed by the language itself.

A class in object-oriented languages is supposed to be a blueprint to create instances that share common behavior and state. A static class is not conceptually a class, but a namespace to other constructs. The choice of the class keyword was unfortunate, and a better keyword could have better communicated its intent; like module, or even namespace. There was no backwards compatibility to be preserved, so this was a bad design decision. VB.NET actually has modules that serve exactly this purpose. And so does F#.

A module would have less clutter and its intent would be explicit; instantiation or hierarchies of modules doesn't even come to mind:

public module ConversionUtils {
  public double ConvertTemperature(
    double fromTemperature, 
    TemperatureUnit fromUnit, 
    TemperatureUnit toUnit) { 
    ... 
  }
}

The result is similar, but without the cognitive load that the class keyword creates.

The usage could be simplified by importing the module (much like a static import in Java); the module name wouldn't need to be specified:

using module ConversionUtils;

...

var temperatureInKelvin = 
  ConvertTemperature(100, 
    TemperatureUnit.Celsius, 
    TemperatureUnit.Kelvin);

No comments:

Post a Comment