The Trouble with Templates
Are you the type of person that believes what you're told? Or do you make decisions for yourself based on critical thinking and experience? In this article, we take another look at one of the bastiens of modern object-oriented programming, the template.
C++ had templates added to it sometime in the 90s, if memory serves correctly. At this point in the language's lifecycle, it was already turing complete and deployed in many enterprise-grade applications around the world. The same could be said of Java before the insertion of Generics. So what was the driving force behind putting these constructs into the language?
Avoiding the Cast
The most-of-cited benefit of templates has to be type safety. For example, it is now possible to enforce at compile time, the types of objects which can be inserted into a collection. Furthermore, there does not have to be a run-time check in Java or C-sharp when the object is obtained from the collection and a cast is performed. So there is a perceived benefit in terms of efficiency as well as type safety. We'll look more closely at this in a minute.
Type safety in collections
Ask yourself as a programmer, how often is it that you place different types of objects into a collection? I would wager the answer is ALMOST NEVER. In fact, it is generally a sign of extremely poor design to put objects which are not related to each other in any way into the same collection. Sure, you might put objects which all implement the same interface, or objects which derive from a common base class into the same collection, those are good uses of the collection. But objects which are not related in any way? I would say, virtually never. So why do we need our collections to be enforced at compile time in order to prevent us from performing such a bone-headed manouver? The vast majority of collections to not suffer from this problem in the first place.
Templates have helped to eliminate the use of C++ and C Macros
OK, I will grant you that this is a benefit of templates. C++ and C macros are overused, (are you listening, Microsoft?). HOWEVER! Most of the times that macros are used in C and C++, an "inline" function would suffice instead. Basically macros can very often be avoided without resorting to templates.
Templates are more efficient
I have read that templates are more efficient because they avoid casting. We will examine this in a subsequent section. I have also heard that it is possible to write code using templates that use fewer instructions to perform the same thing. The most-often-cited example of this is the "swap" function. So, OK, perhaps it is more efficient when you look at the minutiae of these methods. I don't believe that casting is any less efficient in C or C++.
People that argue that templates are more efficient are missing the point. Templates are actually less efficient because they are using much more memory, and because they are wasting much time during the development cycle. When we talk about efficiencies we cannot ignore this dimension.
Templates allow for truly generic implementations
In C and C++, the problem you are often faced with, is that it is impossible to write a re-usable class that works with all objects. This is where templates have helped. However, in Java and C#, there is a common "Object" base class which all objects extend so it is debatable whether templates are needed in these languages in order to solve this problem. It is true that in Java (for example) the basic types of int, char, etc. do not derive from the Object base class. So generics solve the problem of creating a collection which can deal with all of these types.
However, I argue that we have paid a very high price for these marginal benefits.
The Trouble With Templates
Massive increase in compiler complexity
The first, and debatably worst, problem with templates is the massive increase in compiler complexity. This problem lead to all kinds of compiler bugs and crashes during the 90's, with tons of developer down-time. Although it is true that the major compiler vendors have largely gotten their act together with regards to instability, compiling a template-heavy program generally takes the compiler much more time and effort, than one without templates. The cost here is developer effectiveness. Developers often recompile their application thousands of times, so any perceived efficiency increases obtained by templates while doing the actual programming is DWARFED by the massive efficiency loss that comes over waiting for your program to compile for the 1000th time.
Also this problem makes it harder to port C++ applications to new platforms that currently do not have a good C++ compiler.
Addition of bloat to the codebase
Compilers add bloat. Don't deny it, it's true. Whatever you have heard about this, it is an undeniable fact. If you have a template with three different type instantiations, there are three different pieces of code introduced by the compiler, compared with 1 version of the code in the non-template version. It is true that improvements in compilers have reduced the amount of bloat generated by templates, but it is still a big problem.
What's the big deal, you might ask, computers are powerful enough to handle the bloat these days. That view is extremely short-sighted.
Think of all of the embedded, hand-held devices, think of the low-power netbooks. Think of the whole "ubiquitous computer" paradigm. This is a huge market and templates are killing the effectiveness of programs on these platforms because they simply don't have the memory and/or disk space to handle it.
So perhaps over time, those platforms may also become more powerful. But honestly, if your house is messy and filled with junk, what should you do? Clean it up? Or just buy bigger and bigger houses? Consumers are rightly complaining that their operating systems and applications are becoming bloated. The industry seriously needs a reality check.
Are casts really that bad?
I've heard it said, "casts are only used when something is broken". Well, I think that's overstating it a little, don't you? Look, casting in C, and in C++ is par for the course. I've never seen a program that didn't involve some casting. By extention of this logic, it means that all programs are broken. Furthermore, unless you have overridden some operators in C++ (a dubious practice anyway, and a topic for another day), there is no additional run-time penalty for casting an object in C or C++. In Java and C-sharp, I'll grant you there is a tiny outline of a point here, since you can avoid the run-time check that the virtual machine performs. However, again, a marginal benefit.
Ambiguities introduced into the language
From the wikipedia article on templates:
foo (a < b, c > d) ;
"This may be a function call with two integer parameters, each a comparison expression. Alternatively, it could be a declaration of a constructor for class foo taking one parameter, 'd', whose type is the parametrised 'a < b, c >'."
While it is true that not all languages suffer from this problem (noteably D), it is a common problem.
Drastic reduction in code readability
Do I even need to elaborate on this point? Anyone who has seen template-infested code will probably admit that it has an impact on readability and understandability of code. This further wastes my time as a developer, trying to understand a cryptic piece of code.
Bizarre error messages no human can comprehend
This also goes without saying, there has been many times yours truly has wasted hours trying to figure out a bizarre error message, only to find it was something extremely minor caused by template definitions. Again, this falls under "wasted developer time".
For the love of god, why? Stop contemplating your navel and come back the normal world of programming, people! :) Actually it might not be fair of me to criticize this practice since I don't know anything about it. But, I'm not alone in thinking that this programming style is something a bunch of intellectuals do. I have yet to see this used in a project, am still waiting for the practical applications.
If you don't like them, too bad, you have to use them
C++ was supposed to be designed in such a way that its features were optional, i.e. if you didn't want to use them, you didn't have to. And by and large it accomplishes this goal, but only if you as a developer have control over the entire codebase from start to finish.
In the real world, programmers have to deal with 3rd party libraries, and not to mention the STL, so it is inevitable that templates will be forced into your application at some point. Furthermore, even if you don't have 3rd party libraries, and you take the drastic step of writing your own collection objects to avoid the STL, if you are on a large team of people, someone will always dissent and insert templates into the project.
So basically those of us that question the benefits of this are in fact left with no option at all, like it or not.