Metaprogramming: Generation vs. Interpretation
Metaprogramming is really all about raising the level of abstraction of your languages so that you can describe applications more efficiently and (ideally) in a way that would be more comprehensible to domain experts without a programming background. In the ideal case you develop (or borrow!) languages to capture all of the key functional requirements and then make them executable so that there is no difference between the requirements and the application. The hard part of application generation is coming up with just the right grammars, constraints and semantics for those languages and that takes a while. Once you have the languages the question then is "what next"?
Broadly there are two answers. Just as back in the day there was a distinction between compiled programming languages that were turned into assembler and then saved as some kind of binary and interpreted programming languages that were read and turned into machine executable instructions at runtime, you can compile or execute your DSLs.
In general terms "compiling" DSLs means using some kind of code generation to take your DSLs, often merging them with templates to generate scripting in your favorite 3GL language. In general terms, "compiling" DSLs means providing an API that the DSLs can call at runtime or extending the language to provide for in-language DSLs using another mechanism. In practice this is not an either/or choice. Even hardcore code gen enthusiasts will probably have some core framework files they call from a library or copy to every project untouched, and sometimes you will use generation to generate the method calls to your API, so it is more a question of towards which end of the spectrum the balance lies.
Which approach should you consider for your application? As always, "it depends", but here are some heuritstics I've found to be of use.
- Size of Code Base - The more you focus on generation, the more code you will have. I'm not a big fan of code. It is ugly, error prone, specific to a particular 3GL and often hard to refactor, so a focus on framework code will usually decrease the size of your overall code base.
- Readability of Code Base - Unfortunately, general framework code can be quite hard to understand. It'll often take advantage of powerful metaprogramming features that can make it hard to understand and debug. Generated code may be bigger, but it is probably easier for more developers to comprehend.
- Intellectual Property - Do you want to have over to clients the solution to a specific problem or an engine that gives them the ability to solve a whole class of problems. Sometimes code gen allows you to keep more of the "value" of your system in-house.
- Language Limitations - Some things are just too painful to do dynamically in some languages (which is why you see a lot of code gen in the Java world and very little in the Ruby community). If you're hitting a brick wall in interpreting a DSL, sometimes it is just easier to generate some of the code
- More Moving Parts - Bear in mind that if you have a separate generator, you have to keep both the generator and framework code in sync in terms of versioning and it is one more piece of code you have to keep track of. Some developers solve this by building the generator right into the code base which can be a good idea if the intellectual property concerns aren't a major driver.
- Performance - I'm always reluctant to talk about performance upfront, but there are some applications for where performance is going to be a real issue and on the whole generated code will perform better than interpreted. Bear in mind if performance is really important, instead of generating OO code you might want to just gen a lot of down to the metal procedural code as it perform better if you design it just right.
Thoughts?



The goal of software architecture and design is not always to raise the level of abstraction. It is often the case that the abstraction needs to be shifted sideways, or even eased. The exercise is and always will be about domain mapping, taking real world objects, or processes, and representing them in the software domain, in order to manipulate, simulate, observe, and control, in ways that result in usable information. Depending on where you are travelling, sometimes it makes sense to take a car, other times a boat is needed.