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.