The last couple of years I work in PHP, without that being my choice, and naturally I curse all the time about the lack of all those little things that are taken for granted in C#. Today, however, I am going to talk about Late Static Binding, a feature of PHP 5.3 that does not exist in C#.
Late Static Binding, to be put simply, is the ability to override static functions. It is the equivalent of late dynamic binding, ie. the ability to override methods, which is a key feature of object oriented programming.
Let’s see an example.
// PHP Code:
class A {
public static function GetName(){
return 'A';
}
public static function SayHello(){
return 'Hello from '.static::GetName();
}
}
class B extends A {
public static function GetName(){
return 'B';
}
}
A::SayHello(); // returns 'Hello from A'
B::SayHello(); // returns 'Hello from B'
This seems to be very natural. Had I used dynamic methods, that would have been straight forward, because dynamic methods are always late-bound. However, I want to use static functions. This is something that is not supported by many languages. In PHP, this behavior is possible with the use of the static:: scope, which is late-bound.
On the other hand, this is not possible in C#. Let’s translate the code, word by word:
// C# Code:
public class A {
public static string GetName(){
return "A";
}
public static string SayHello(){
return "Hello from " + GetName(); // here is the problem
}
}
public class B : A {
public static string GetName(){
return "B";
}
}
A.SayHello(); // returns "Hello from A"
B.SayHello(); // returns "Hello from A"
Oops! The static function GetName() is early bound, which means that it is always resolved as A.GetName(), even if it is called from the static context of the class B.
A pattern to the rescue
The problem is simple. The base class does not know which is the current static context and it always assumes it to be A.
This can be solved with Generics. The current static context can be passed as a generic parameter to the base class, so the class A can become A<T>. The generic parameter T is the current static context. So the class B has to extend A<B> because we want all the the static calls to be bound to B.
However, adding a generic parameter to a class changes the class signature. In other words, A is not the same as A<T>. Yet, in C#, it is possible to have both! So, the class A has to extend A<A>, because we want all the static calls to be bound to A! Remember, that this is possible because A is not the same as A<T> and nothing forbids us from setting T to A.
Furthermore, the parameter T has the type A<T>, which means that it follows the interface of A<T>. That’s exactly what we want to achieve. All static function inside A<T> can be called from the static context of T. So, instead of calling GetName() which is early bound, we can call T.GetName().
All these may sound like a vicious circle, but the following code actually compiles and gives the solution we want.
// C# Code:
public class A<T> where T : A<T> { // vicious but compiles
public static string GetName(){
throw new Exception("Not implemented");
}
public static string SayHello(){
return "Hello from " + T.GetName();
}
}
public class A : A<A> { // cool, right?
public static string GetName(){
return "A";
}
}
public class B : A<B> {
public static string GetName(){
return "B";
}
}
A.SayHello(); // returns "Hello from A"
B.SayHello(); // returns "Hello from B"
So, the trick here was to separate the class into two parts. The first part will have a generic parameter which represents the current static context and will contain all the static functions. The other part will be the ordinary class which will continue to work as if nothing has changed.
Stay tuned, in the next post I am going to analyze a trickier example with more levels of inheritance.