# Monday, 26 June 2006

A few days back, Jeff commented that he wasn’t convinced about the value of putting an object model on top of what should be simple string generation.  His example was using XmlTextWriter instead of just building an XML snippet using string.Format. 

I got similar feedback internally last week when I walked through some of my recent CodeDOM code.  I was asked why I would write

CodeExpression append = new CodeMethodInvokeExpression(sb,"Append", new CodePrimitiveExpression(delim1));

instead of

CodeExpression append = new CodeSnippetExpression(“sb.Append(delim1)”);

It’s a perfectly reasonable questions.  I’m using the CodeDOM’s object model, but the reality is since we’re an all-C# shop, I’m never going to output my CodeDOM-generated code as VB.NET or J#.  So I could just as easily using a StringBuilder, and a bunch of string.Format calls to write C# code and compile it using the CodeDOM’s C# compiler.  It certainly would be simpler. 

The same is true (as Jeff points out) for XML.  It’s much easier to write XML using string.Format, or a StringBuilder. 

If nothing else, I personally find that using the object-based interface makes me think harder about the structure I’m creating.  It’s not really much less error-prone that writing the code (or XML) by hand, it just provides a different way to screw up.  What it does do is force you to think at a higher level of abstraction, about the structure of the thing you are creating rather than the implementation.  You may never need to output binary XML instead of text, but using XmlTextWriter brings you face to face with the nauances of the structure of the document you’re creating.  Writing a CDATA section isn’t the same as writing an element node.  And it shouldn’t be.  Using the object interface makes those distinctions more obvious to the coder. 

However, it’s definitely a tradeoff.  You have to put up with a lot more complexity, and more limitations.  There are a buch of contructs that would be much easier to write in straight C# than to express them in CodeDOM.  It’s easy to write a lock{} construct in C#, but much more complex to create the necessary try/catch and monitor object using the CodeDOM. 

I was, in fact, forced to resort to the CodeSnippetExpression in one place, where nothing but a terniary operator would do.  I still feel guilty.  :-)  Maybe it just comes down to personal preference, but I’d rather deal with the structure than the syntax even if it means I have to write more complicated code.

Tuesday, 27 June 2006 11:55:41 (Pacific Daylight Time, UTC-07:00)
In a former life, I used to write reams and reams of CodeDom code.

By the end, I was 100% convinced that SnippetExpressions were evil and that it was worth the effort to actually write out the correct CodeDom AST. There were a few reasons for this:

1) At some point, someone will ask you to spit your code out in something other than C#. We ran into more than a few customers who had enterprise-wide edicts that all code Must Be Written In VB.NET -- even the generated stuff. Rather than spending a lot of effort to cut through the red tape, we just caved. Fortunately, this was easy because we'd abstracted everything through proper CodeDom.

2) Because the CodeDOM object graph mirrors the AST produced by the language parser, writing to the CodeDOM graph greatly increases the chances that your generated code will actually compile the first time :) Because SnippetExpressions are basically just opaque strings, you're essentially programming via string concatenation and all the fun that entails...

3) Following on from (2), sticking to the strict AST representation of 'pure' CodeDom opens up some interesting possibilities for transforming one AST rep into another AST rep. Sort of XSLT, but for code. CodeDOM is far from the best intermediate rep, but sometimes its all you have (for example, taking the CodeDOM graph provided by the WsdlImporter API's and then doing some form of post-processing to augment the output). Again, the opacity of SnippetExpression will really hurt you here.

Lots of folks complain that CodeDOM isn't complete, but I'm not convinced that's the case. I have yet to find a core semantic that wasn't expressible in some form via a pure CodeDom graph. For example, the ternary operator scenario you describe could be equivalently represented by introducing a temporary local variable and using some 'if' statements. Sure, lots of syntactic sugar is missing (e.g. language-specific idioms like 'lock' and 'using') but I've found that those semantics are fundamentally expressible in CodeDOM (definitely 'possible', but not necessarily 'easy').

Sigh...I think part of me misses metaprogramming...
Comments are closed.