Generics as Type Constructors

From Don Box:
 
The CLR began its life with three fixed type constructors:
 
  • Array (T[])
  • Managed Pointer (T&)
  • Unmanaged Pointer (T*)
 
Each of these type constructors acts as an operator on another type and allows you to construct new types without an explicit definition.
 
For example, given this type:
 
public struct Person { public string SSN; public double Age; }
 
I can now ask the CLR to create new types by applying one or more type constructors:
 
Console.WriteLine(Type.GetType("Person[]"));
Console.WriteLine(Type.GetType("Person*"));
Console.WriteLine(Type.GetType("Person&"));
Console.WriteLine(Type.GetType("Person[][]"));
Console.WriteLine(Type.GetType("Person[][]&"));
Console.WriteLine(Type.GetType("Person[][][][]&"));
 
The six types that are loaded by these statements have no a priori definition - rather, they are synthesized out of thin air by applying one or more operators to a "real" type.
 
Generics in the CLR allow anyone to write a type constructor. For example, consider this generic type:
 
public struct Named<T> {
  public T Value;
  pubic string Name;
}
 
Given this new "operator", I can do the following (note that GetType uses [] not <> for parameters):
 
Console.WriteLine(Type.GetType("Named[Person]"));
Console.WriteLine(Type.GetType("Named[Person][]"));
Console.WriteLine(Type.GetType("Named[Person[]]"));
Console.WriteLine(Type.GetType("Named[Named[Person]]"));
Console.WriteLine(Type.GetType("Named[Named[Named[Person]]]"));
 
which is roughly equivalent to this more direct version:
 
Console.WriteLine(typeof(Named<Person>));
Console.WriteLine(typeof(Named<Person>[]));
Console.WriteLine(typeof(Named<Person[]>));
Console.WriteLine(typeof(Named<Named<Person>>));
Console.WriteLine(typeof(Named<Named<Named<Person>>>));
 
As this example shows, Named<T> is yet another operator I can compose with other operators (both the built-in and user-defined type operators). 
 
This compositional style of taking two or more abstractions that know nothing about one another and combining them to get higher-order functionality has really changed the way I look at designing object models. 

No Comments