Hacking Generics


One of the C++ features I ever missed in C# are the templates. Every time I cast the result from an ”IList” or an ”ICollection”, or when I code a custom collection, feels like I’m loosing my time.

I have some math intensive applications developed in C#, and I use some classes like ”Matrix” or ”Vector” to perform some calculations. But no every application needs the same precision for the components of those math entities. Some times I need doubles, but when it’s not the case, using floats or even integers could be a big performance hint. If I were programming in C++, I can use a ”Matrix” class and specify the type I want to use each time, and reuse all the implementation. But there is not solution when programming in C#. It doesn’t exist any pattern or OOP tip that can help us. (Ok… may be some Smalltalk or functional languages programmers start laughing at this point).

Now that Whidbey is coming and generics are become a reality, one can start dreaming how to solve that problem. But, as I can prove later, not all that shines is gold.

I run Visual Studio Whidbey for the first time, and I think that generics are the first feature I will test. I start a new project, and start coding almost without thinking:


public class GenericsTest
{
public T Add(T first, T second)
{
return first + second;
}
}

I try to compile and… Oops! An error explains me the first difference between templates and generics. With generics, “T” will be an ”Object” until I cast to something more representative or restrictions are applied over it using the new keyword: “”where””. I start reading the docs about which restriction will be useful and… oops again! Restrictions can be interfaces, classes or the keyword “”new()”” specifying that “T” must have a default constructor. Nothing useful this time, because numeric types don’t have a common supertype (Smalltalk people smiles again) and even if it existed, operators are implemented as static methods in C# so they will not be inherited.

After some time going into generics undergrounds, I learn how they are implemented in IL and CLR. Removing the problematic return sentence and replacing with a ”return T.default” to avoid more errors the class can be compiled successfully now, and the disassemble looks like that:

.class public auto ansi beforefieldinit
GenericTests<([mscorlib]System.Object) T>
extends [mscorlib]System.Object

{
.method public hidebysig instance !0 Add(!0 first,
!0 second) cil managed
{
// Code size 14 (0xe)
.maxstack 1
.locals init (!0 V_0,
!0 V_1)
IL_0000: ldloca.s V_1
IL_0002: initobj !0
IL_0008: ldloc.1
IL_0009: stloc.0
IL_000a: br.s IL_000c

IL_000c: ldloc.0
IL_000d: ret
} // end of method GenericTests::Add

As you can see, “!0″ means the first type parameter “T”, and the CLR will replace all theirs occurrences with the type specified when an instance is created, and nothing else, like templates do! So, how can we cheat the C# compiler to produce the desired output? Maybe there is no solution at this time, but we can write the code in IL! Or at least, use some ildasm and ilasm.

I rewrite the class thus:

public class GenericsTest
{
public int Add(int first, int second)
{
return first + second;
}
}

After compiling and disassembling, I replace all “”int”” occurrences with “!0″:

.method public hidebysig instance !0
Add(!0 first,
!0 second) cil managed
{
// Code size 8 (0x8)
.maxstack 2
.locals init (!0 V_0)
IL_0000: ldarg.1
IL_0001: ldarg.2
IL_0002: add
IL_0003: stloc.0
IL_0004: br.s IL_0006

IL_0006: ldloc.0
IL_0007: ret
} // end of method GenericTests::Add

I compile again with “ilasm”, and reference it from another project. Now I can create instances like ”GenericTests”, ”GenericTests” to get successful results, or even try ”GenericTests” to see what disastrous can be the trick, but with some precautions it will be so useful.

I know that the solution isn’t so elegant. Maybe nobody wants to disassemble their code each time and recompile again, but some post-build actions can help.

I hope MS enhance generic restrictions and permit something like that:


public class GenericsTest
where T : operator+
{
...

What do you think?

Leave a Reply

Your email address will not be published. Required fields are marked *


− 1 = three

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>