Aside from reverse engineering FPGA bitstreams I've finished (Yes!) another pending programming project last week. I was helping out a fellow programmer, let's call him Bob, who was busy doing other things and had no time to hack away a set of high-prioritized items from his TODO list. So I pulled these items from his list over to mine. I have plenty of experience doing these troubleshooting jobs and I always feel like a surgeon carefully inspecting the innards (source code) of the patient (application) before cutting out tumors (bugs) or implanting organs (patches)...
Ok, to come back to the problem: I was supposed to extend a desktop application that was designed and written from ground up by Bob two years ago in C++ (using
Qt). Hmmm...C++ and templates. I can hear your brain working now. Right, we're not talking about document, XML or whatever templates here. It's the well known C++ programming language feature (see
Template Metaprogramming). I use it regularly. It's a great feature if the compiler fully supports it. If you're familiar with templates feel free to skip the next paragraph.
Templates implement the concept of parameterized types in C++ (
Bruce Eckel, Thinking In C++). It's a syntax extension that tells the compiler how to define a type from a generic type declaration. Wow...that was abstract. How does it work? The first time you instantiate a template with a given type (as parameter) in your code this parameter is inserted by the compiler into your template declaration and creates an entirely new type. Ideally templates are designed in such a way that you can throw almost every type on them (as parameter). Yes, even user-defined types. Think of it as another way of reusing code besides the
OOP based inheritance approach. The syntax can also be applied to function definitions (aka function templates). Templates are perfectly suited for container classes like lists, queues etc. of arbitrary objects. Personally, I've used templates in digital signal processing algorithms to create number format independent filters amongst others. Other classic/good examples are the
C++ Standard Template Library (STL), the
Boost C++ libraries or Intel's
Threading Building Blocks (TBB).
The challenge with templates is that it's very convenient and easy to use them but significantly harder to create them in a structured and maintainable way. Did I mention that templates are entirely implemented in header files? That may become an issue as I'll explain later. Now guess what happened...the app I was working on was full of templates. Driven by the idea of increasing runtime performance Bob applied the template concept to nearly 100% of the data path related code. His intention was to let the compiler optimize e.g. (inline) nested function calls introduced by the object hierarchy and flatten them out at compile time. No virtual function lookups and stuff in the binary...anymore. Highly instruction level optimized code. The perfect solution for maximum performance...
Problem1: The template concept is no silver bullet for your performance problems. The 80/20 rule still applies: 80 percent of the execution time is spent in 20 percent of your code. (Or was it 90/10?) Use a profiler and analyze your code carefully
before delving into advanced and unreadable templates of templates of template constructs.
Problem2: While it might be a (good) academic exercise to create an entirely template based object hierarchy to gain a deeper understanding of the language concept it's probably a bad idea to apply this pattern to your entire framework. First, this makes it hard or even impossible to put your framework later in a library and second, the guy next door (patching your stuff) appreciates readable code.
Problem3: Have you ever tried to debug and/or patch this stuff? When 98% of the files are header files you'll trigger a recompile of the entire project just because you've changed a variable name from i to tableIdx, and not to mention the weird error messages you might get in seemingly unrelated sections of the code (although compilers got better and precompiled headers may reduce the pain a bit). Yes, I'm exaggerating here but you're getting the point.
Don't get me wrong. This is no rant against templates! Letting the compiler write type-safe code for you is of great value. Also, generic datatypes tremendously reduce the amount of duplicated code. But be careful when using this powerful language feature. Use it only where applicable i.e. to maximize code reuse, restrict it to subsets of your framework, keep in mind who might read/use the code and please please don't misuse it for your global optimization strategies.
You want to know the end of the story? Well, just another surgical intervention.