Joseph Cooney's Weblog


Should an O/R mapper also be a code generator? A code-gen fan answers

Steve Eichert asks should an O/R mapper be a code generator? and makes the assertion that it should not. I don't know a great deal about O/R mappers, but I have spent some time thinking about the merits of design time vs. run-time code generation (and some of the same things apply here I think). There is a certain class of bugs that can be caught by compile time type checking that cannot be caught at compile time if you're doing things “dynamically” (either dynamically generating assemblies with CodeDOM or Reflection.Emit, setting properties reflectively etc). Even casting can introduce bugs into your application that could be detected by compile time type checking. The less of it you have to do the better. Another advantage of generated code is that it is usually easier to step through and debug vs. slightly more esoteric reflection code (and WAAAY easier to understand + debug than assemblies created with CodeDOM or Reflection.Emit on the fly). Reflection is also slow (the number 50 is popping into my head as in 50x slower, but I can't find a URL to back that up right now).

Altho Frans seems a little “tense” in some of his comments I agree with a lot of what he is saying. The only time I ever look at generated code is if I'm using a codegen tool for the first time and want to get a feel for what sort of output it produces (or if there is a bug in a generator). Like Frans I also have no problem with verbose generated code - if it could be elegantly written in 5 lines (and handle all cases) then I would hardly write a generator for it. Code generation is just one re-use technique that can be used when other types of re-use (like encapsulation or inheritance) cannot be used. Also I am firmly of the opinion that generated code should never be edited. Inherit from generated code, build in extensibility points into your generated code, but don't edit it.

I noticed in some of the comments in this post asking about methods for creating assemblies on the fly. The main ways of doing this in .NET that I know of are Reflection.Emit, creating a CodeDOM object graph and passing it to a class that implements ICodeCompiler, or building a string on the fly and passing it to an ICodeGenerator. My brother Dominic has some nice demos of Reflection.Emit in action from a talk he did at the local users group about 6 months ago. CodeDOM is one of the more mind-bending APIs in .NET, and has a number of limitations, and can result in some fairly verbose generator code, but you can produce useful things with it.

As always YMMV, not available at all stores, may contain traces of nut, contents may have settled during shipping etc.

Comments (4) -

I think you've hit on one of the main advantages of code generation vs. creating dynamic assemblies at runtime.  Debuging dynamically generated assemblies can be a major pain in the butt.  

I also agree that if your using a code generator you shouldn't touch the code, since if you start editing it, you can't re-run the generator without losing some of the work you've done.  

With that said, I still prefer runtime generation of dynamic assemblies over code generation.  I wonder if there's a way around the debugging limitations?  Also, I think having a configuration flag that tells the O/R framework to output the code it generates is a good idea, similar to what you can do with the XmlSerializer.  


Re: Debugging dynamic assemblies - I agree the ability to optionally output source code as well as a compiled assembly is definitely a step in the right direction (altho maybe if you're really familiar with reading IL it wouldn't make too much of a difference - I know my brother Dominic is fairly fluent). The big advantange of CodeDOM is the ability to produce code in different languages - if that is not an important feature then string building is definitely much easier. There are no guarantees with a CodeDOM object graph that you will produce "valid" code or anything.

Dynamic code generation is obviously alluring - since everything is always being regenerated it is always all "in synch". There is the startup performance hit (like ASP.NET, XmlSerializer etc), and it does feel more fragile to me, but it certainly has interested me in the past. It will be interesting to see where your O/R mapper ends up.

I guess custom hooks in generated code (such as in Alachisoft's TierDeveloper) justifies code "in" the generated layer?


I don't think you have to generate an entire tier. I think custom written code (either hooks into helper classes or subclassing) is a good way to handle "edge cases".

Comments are closed