Monday, April 7, 2008

T4 and something to keep in mind...

A friend of mine recently did a post on the T4 framework (Text Template Transformation Toolkit) here. I had been following the technology for a little bit but I haven't had the opportunity to actually use it (just literature till now). After reading that post, I decided it was time to put on the water-wings and give it a whirl from within VS2008 (no additional downloads for VS2008). Needless to say, its pretty good. Honestly, its about time they built a template engine directly into the IDE. I think this will encourage a host of folk to rally around the banner of Code Generation goodness.

With all that said, there is a small thing to keep in mind. It's something that, when you think about it, is quite obvious, yet because of its nice "integration" with VS2008 its easy to overlook (well for me it was anyway).

What I wanted to do was, quite simply, using code inspection, create a set of interfaces and base implementation classes for a set of types. For example:

public interface INodeVisitor
{
bool Walk(BlockStatement node);
void Postwalk(BlockStatement node);

bool Walk(ScopeStatement node);
// .... continue on
}



I thought it would be a funky "first time" use of the template engine as if I added a new type, both my IVisitor and the various default implementations could be generated. I was quite proud of myself for finding such a nice "practical" use for T4 (I really didn't want to do the atypical "generate the business objects from the database" routine). The problem is, even though the template "looks" like it is part of your solution - it is important to realise that only the generated file is actually part of your solution, and not the template itself (ok, technically, that's wrong. The template is part of your solution, its just not within the same "code scope" - if I can call it that...). That is to say, you don't have access to types, from within the template (via template statements and/or features), that are defined within the same solution.



The reason for this is actually very simple and straightforward. The default T4 compiler kicks in via an "external" command line call with, compiles the template file, applies the transforms and generates your file. Therefore, like I have mentioned, its important to keep in mind that the template compilation and file generation happens outside of the scope of your own solution's compilation cycle. However, the generated file will still be compiled as part of your solution's normal compilation cycle.



Now before everyone pipes up at once, I do realise that using template directives, you can reference another assembly. The only issue is, that from what I saw, it required the full path to the assembly (i.e. "C:\development\someproject\bin\debug\somedll.dll"). I am not a huge fan of this, because of the potential for different build configurations (do you import the debug version of the assembly or the release version?). It just felt a little dirty to me. Also, we wont even step into issues like what happens on the first time build when the assembly doesn't yet exist. I guess you could use the hostspecific="true" and try and interact with the code model using the EnvDTE (from what I know the Visual Studio T4 host implements IServiceProvider) but I haven't gone that far just yet. Something to look into. Perhaps the topic of another post...



Anyway, like I said, nothing major, and not something that should stop anyone from using T4 - generally most (if not all) the other template engines should suffer the same limitation. It's just something to keep in mind when designing/creating your templates. It's way to easy to assume that because its within your solution explorer, that it has the built-in ability to access all types available within your assembly.



To sum up. T4 - I like it. I'll probably make more use of it where I can - especially in the area of boilerplate test cases - even if I have to "full path" the assembly reference (or use some DTE magic - is that even possible?) The simple fact that I don't have to bounce out to another application to compile the template and that there are no additional downloads, makes it a winner for me. It's really useful when you just want to quickly whip something up to "fill that gap" and not have to alt-tab for it and contend with project file changes and reloads...



My only gripe? No built-in intellisense! I guess that if you don't want to have download and install something like this T4 Editor, template edition is going to have to be done without all our new fan-dangled toys and back to the notepad roots! (for now, at least ;D).

No comments: