Why is specialization in C# generics limited?

Viewed 1619

The question "What is reification?" has a comment on C#'s generics:

Type information is maintained, which allows specialization to an extent, by examining type arguments using reflection. However, the degree of specialization is limited, as a result of the fact that a generic type definition is compiled before any reification happens (this is done by compiling the definition against the constraints on the type parameters - thus, the compiler has to be able "understand" the definition even in the absence of specific type arguments).

  • What does it mean by "specialization"? Is it not the same as instantiation of a generic type with a specific type argument?

  • What does it mean by "the degree of specialization is limited"?

  • Why is it "a result of the fact that a generic type definition is compiled before any reification happens"?

3 Answers

What does it mean by "specialization"? Is it not the same as instantiation of a generic type with a specific type argument?

Author explains in the portion of his answer dedicated to Java generics that

specialization of a generic type [is] the ability to use specialized source code for any particular generic argument combination.

In other words, it is an ability to do something special if a generic type parameter is of a specific type. Supplying an implementation of List<T> that represents individual elements as bits when you instantiate the type as List<bool> would be an example of specialization.

What does it mean by "the degree of specialization is limited"?

Author means that although you can write things like

if (typeof(T) == typeof(bool)) {
    ...
}

your abilities to respond to a combination of type arguments are limited, because any decision on a type combination has to be made at run-time.

Why is it "a result of the fact that a generic type definition is compiled before any reification happens"?

Because reification is done in CLR, well after C# compiler is out of the picture. The compiler must produce a generic type definition for CLR to use as a "template" for making closed constructed types for instances of a generic class.

I believe the meaning is as follows:

When you define a generic type e.g. MyGenericType<T> your definition has to make sense for any value of T, as the generic type is compiled before you actually use it in a specific implementation ("the degree of specialization is limited, as a result of the fact that a generic type definition is compiled before any reification happens").

Later on, when you actually use a MyGenericType<int> the compiler/jit will create a new class which is pretty much MyGenericType<T> with every mention of T replaced with int. This is the process of reification. This means that at runtime, you can use the fact that the generic type is using an int, but your ability to make use of this (specialisation) is limited, since when you defined MyGenericType<T> you didn't know this.

Specialization is used as antonym to generalization. When you created a generic type, you generalized a type definition. When you initialized it with a type, you specialized the compiled generic type to be able to create object of the type at run-time.

IL compiles the generic type. At runtime, this compiled generic type is combined with specific type argument to produce an object of the specified class.

Yes, specialization is same as instantiation of a generic type with a specific type argument at runtime.

With generics, come constraints which basically fix the scope of generic type. You can tell that by defining that T can be a struct, class, or has to have some specific base class etc. You cannot create a class instance which is not allowed by the constraints defined on the generic type.

You can initialize the same generic type definition with a int, string or another class, if it satisfied the constraints in the generic class. It cannot directly create an object of the class with T, not yet replaced by a defined type (primitive types like int, string, or your custom class or interface) and your code inside should be compatible to type being passed in as T for it to work.

Refer (Links from same question you mentioned above):

NET Generics and Code Bloat

Generics are not templates (as in C++)

Related