Some programming languages give you the power to generate code dynamically at run-time. To generate code or not to generate code? That is the question. In most circumstances, as in 99.99% of the time, I would say ‘NO!’ all capitals with an exclamation point. It is a very exciting path to start going down, but it will lead you to a dark and scary place I like to call the generated code Gingerbread House.
Disclaimer
I’m not going to go into detail about code generation as that isn’t what this post is about. I’m also only looking at .NET in this post. I’ll do future posts about Python and SQL as well.
The discovery!
Towards the end of last year one of my colleagues posted a question on Yammer asking if anybody had any experience in dynamic code generation. It made me think back to the time when I discovered the System.Reflection.Emit namespace in .NET and thought it was the best thing since, well since the inclusion of the Slice() method in the Food.Bread namespace.
Being the young and naive developer I was I couldn’t wait to use it in a project. Using .NET Reflector I could write C# code and then go and see what the Intermediate Language(IL) looked like. I was well on my way to the generated code Gingerbread House.
When it came time to debug my creation I realised what I had created, an absolute nightmare. I still get goosebumps thinking about it.
Why not then?
Before I get into the reasons of why code generation, and code generation in .NET specifically, isn’t a good idea I just want to show you what it looks like. Below is some sample code, the IL is from a Microsoft ‘How to’article.
// This code squares a given number ILGenerator il = squareMethod.GetILGenerator(); // This is the actual IL code il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Conv_I8); il.Emit(OpCodes.Dup); il.Emit(OpCodes.Mul); il.Emit(OpCodes.Ret);
For those of you familiar with Assembly language the values being passed into the Emit() method might look somewhat familiar. These are the low, low, low level commands, the bare bone commands of .NET. If you just look at the IL do you have any idea what it is doing or how to change its functionality? If I was busy debugging and came across this code I would most certainly spill my coffee and exclaim ‘What is this dark magic I look upon?’.
Using code generation, as in the above example, means your code is:
Unreadable to all but the very few who understand IL.
You can’t easily debug the IL code like you would the other code around it.
The two points above mean the maintenance of the code is going to be an absolute nightmare.
Something to reflect on
Of course there are reasons for dynamic generation at run time, but not dynamic code generation (generating the IL code). One of the reason for using dynamic generation is for Dependency Injection (DI) and all that goes along with it. DI frameworks make use of reflection which means that they don’t generate code dynamically, but rather instantiate the required types dynamically.
It means that although a developer might not exactly know which implementation of a type is going to be instantiated at run time at least the reflection code and the actual implementation of the types are easily readable. Nobody is going to be spilling any coffee and most developers understand the way reflection works.
I’m definitely going to have future posts about code generation, but for now that is it. What are your thoughts on code generation in .NET, the misunderstood stepchild or a devil in disguise?
Comments