This page contains things which ChrisHandley has deleted, because he doesn't feel comfortable permanently erasing stuff without giving other people a chance to undo it. Beware that this page will be emptied from time-to-time, so please undelete stuff you want while you have the chance! :-)
Templates are a smelly invention(?) of CeePlusPlus and would be avoided except that they are there to patch major flaws in CeePlusPlus's design. Discuss!
Actually, templates (generics) weren't an invention of CeePlusPlus at all. AdaLanguage had 'em first; many statically-typed FunctionalProgrammingLanguages have had GenericPolymorphism? for quite a while as well.
To get things rolling, here's my own take on why they smell:
- They implement statically what can be achieved nearly as efficiently dynamically using OOP polymorphism (at least in a language that isn't broken by design).
- They are incredibly difficult to understand & use properly because they don't clearly separate the usual dynamic operations of a program from the complex static (compile-time) operations that happen before the program is run.
- The extra performance gained from using templates is disproportionate to the effort required to use & understand them.
- Lots of experience with C++ suggests otherwise; despite the flaws in the C++ implementation.
- The tortured explanations I've read in the C/C++ Users Journal suggests otherwise to me. :)
- They make it trivial to (accidentally?) increase the size of the executable by nearly any multiple. This potentially means the program will perform worse because it no-longer fits in the processor's cache, even for Intel's monster CPUs.
- True for early implementations of C++ coupled with brain-dead linkers, which resulted in duplicate instantiations of the same template being present in the resultant executable. Much less true today - in modern C++ environments, you should only get only one copy of any particular template instantiation..
- This point was mainly theoretical for me (i.e. a good guess), but it still sounds horrendous from your description.
- They don't totally fix what they were meant to because CeePlusPlus doesn't use reference semantics (i.e. primitive types & pointers are treated differently, so you can't have one template that handles both).
- This is orthogonal to templates. JavaGenerics don't have this problem.
- Okay, suppose I meant CeePlusPlusTemplatesSmell? ...
--
ChrisHandley
I've done a lot of work with C++ templates, and although I have lots of complaints about them, I don't think a single one of the objections above holds water:
- I've never seen a convincing argument that run-time typing and run-time polymorphism can be as efficient as static typing. The difference might not matter for many applications, but for some it does.
- I never said they were as efficient, I said they were nearly as efficient (in most cases).
- Point taken.
- I've never once been confused about what was occurring at compile time versus at run time. If someone finds himself confused by this when using C++ templates, I hazard to guess that he doesn't have a clear enough model in mind of how the language works to be messing with advanced templates.
- Ok, my problem is that CeePlusPlus's templates model is too complex, like pretty much everything else it does. IMHO a feature is only useful if it is easy to use.
- No, if anything the problem is that templates and the mechanisms to support them are too minimalistic, thus making implementation of even moderately complex systems of template complex. I contend that your humble opinion is wrongheaded; not every programmer has to make use of every feature in a language. Advanced features can be used by advanced programmers to build libraries and services that are easy to use.
- Thus spake a true HackerWizard?, from which all mere mortals cowered in fear! :-)
- Further commentary on AllFeaturesShouldBeSimple.
- Templates can in fact help make a program very efficient; when used to write libraries, the effort is amortized whenever the library is used.
- As pointed out above, the "template bloat" problem generally no longer is.
- From what I understand, C++ still copies the whole templated class each time you use the template which is parameterized by a new (previously unused) type.
- That's true, but the copies are elided later. And the copies are necessary because the types differ in their memory layouts, and C++ (and C) allow you to deal with types by value, reference, or pointer. This complexity is exactly what allows the C languages to generate more efficient code than uniformly run-time typed languages can; the latter in turn can implement generic code more efficiently because (almost) all types are treated similarly at a low level. A careful template author can factor out common code himself. However, it's generally not an issue anyway because in almost all C++ compilers, template code will be inline, which means that the code is copied (and optimized in-place) on every use anyway! Which is usually fine because template code is often performing very basic manipulations that optimize away nicely. (One could argue in fact that a lot of template code is doing nothing but accommodating the compile-time strict typing system; I refer you to the numerous debates on run-time versus compile-time versus strict versus weak typing...)
- Since I don't believe in efficiency at all costs (hence my dislike of CeePlusPlus), including the cost of difficulty-of-understanding, I don't think much more can be said... except that I remain unconvinced that Templates are significantly more efficient than Generics.
- You can't compare the two directly, since the languages' execution models are quite different. But I can assure you that C++ is inherently more efficient at some things than Java, so templates will be more efficient than generics when they're applied to those same domains.
- Depending on what you're doing, it is quite possible to write templates that work with both built-in and user-defined types.
- Wish I'd known how to do that, as it would have saved me lots of bother, but I suspect it'd require lots more CeePlusPlusBlackMagic?.
- Again, it depends what you're doing. For more complex cases, you might need to use tricks like partial template specialization or overloading, which arguably means that you actually have more than one template. Without knowing what you were doing, I can't say if that would have been necessary.
The main problems that I see with C++ templates are:
- Horrid syntax.
- Agreed, but given the sorry state of the C++ grammar, I'm not sure what I'd have done differently. Actually, the biggest problem with the angle bracket implementation is that >> and > > are not equivalent (the first is the rightshift/extraction operator, the other two > brackets), which is UgLy. Of course, Java is grabbing the angle-bracket implementation for themselves.
- One good thing about the angle brackets is they tell you that "this is being evaluated at compile time, no matter what".
- A lack of built-in compile-time primitives for examining and inferring types.
- Not really true; you can use TraitsObjects? for that.
- Yes, I'm aware of this; see my comment right after this list. And TraitsObjects? are not built-in, hence the awkwardness in using them. -- DM
- Uneven implementation, even now in 2004.
- This isn't a fault of the language standard itself, it's a fault of implementors. But if you have the latest version of MSVC, GCC, or any major C++ compiler that still is being worked on; it ought to support templates fully. If not, upgrade your compiler or switch vendors. The standard has existed for over five years now...
- I use mainly VC 7.1, and although compliance overall is quite good, there are still some problemareas. You won't run into them often, but they are there, and it is quite possible to get the compiler to crash. (It should be obvious that this isn't a problem with the language standard. Duh!) -- DM The problem with the language standard is that it's so complicated and fraught with difficulties that no one has yet implemented it properly.
- Subtle problems with name lookup. This plagues not only templates, but also operator overloading et al. However, the problems tend to be more bothersome in the context of templates.
The second problem has been addressed to an amazing degree by various libraries, but they are torturous to write (and read), and the syntax for using them is awkward.
For the kind of work that I do these days, the degree of efficiency that can be achieved by C++ templates really isn't important. I use them more in cooperating systems of templates to create library interfaces that extend the language, or in smaller independent chunks to avoid code duplication. This sort of work would likely be far easier in a language like Lisp. But I see C# in our future -- which actually will probably be fine for the bulk of our application, but I think that I'll miss the expressive power of a more complex language.
-- DanMuller
Having read-up on Generics as implemented in Java (from http://java.sun.com/j2se/1.5/pdf/generics-tutorial.pdf ), I have to say that Generics are great, and do exactly what Templates should have done in CeePlusPlus. In particular, I found this very interesting:
: "It [the use of generics in Java] is misleading, because the declaration of a generic is never actually expanded in this way. There aren't multiple copies of the code: not in source, not in binary, not on disk and not in memory. If you are a C++ programmer, you'll understand that this is very different than a C++ template."
What this means is that Java's Generics are simply static (compile-time) checks, rather than
CeePlusPlus's way of duplicating whole classes.
In CeePlusPlus, as Templates perform static (compile-time) code generation that is not dissimilar from macro expansion (something else that Java cleverly avoids), they unfortunately get (mis?)used by lots of CeePlusPlus wizards to do very clever (and very cryptic) things. So if you like ultra cryptic things, then it is a Good Thing (but I don't, so it Smells).
In summary, Generics are great, Templates smell.
-- ChrisHandley
Not to be rude, but it appears that you have formed your opinion (regarding Java generics) on the basis of an article or two....
An interesting comparison can be found at BruceEckel's blog, http://mindview.net/WebLog/log-0050. Bruce (the author of ThinkingInCeePlusPlus, ThinkingInJava, and a recent convert to PythonLanguage) doesn't much care for the Java implementation.
Previous rebuttal removed, since I need to look at this much closer...
(currently I am (again) thinking Java's way is better)--ChrisHandley
I don't understand this obsession with the copying that's supposedly going on in C++. It's an implementation detail; conceptually, that's exactly what happens (in both Java and C++), but whether it actually happens or not is an implementation and quality-of-implementation detail. In that sense, the quote above is simply incorrect; there's nothing inherent about C++ templates that requires copying anything at all. With modern C++ compilers, it's rare to hear anyone complaining about bloated sizes of the final program due to templates. -- DanMuller
Fair enough. I don't claim to be an expert on Templates, but from my understanding of them, it seems that CeePlusPlus can use Templates to do far more things than Java can do with Generics. If one really wants, one can on-purposely use Templates to generate lots of code (in a similar way to macros), and this is certainly very clever - but I hold the view that a feature should never be overly complex (obtuse), and this is my problem with Templates (aside from their probable size inefficiency & horridly complex compiler implementation). I suspect all CeePlusPlusWizards? will disagree with my AllFeaturesShouldBeSimple principle, so we might as well stop the discussion here :-( -- ChrisHandley
BTW, if something is difficult to implement in a compiler, it is often difficult for the user to fully comprehend too. I believe this holds very well for Templates.
Long ago (which is when I lasted work with them), templated C++ code would generate humongously long symbols. While this is an implementation problem, it did make life hard for us poor coders at debugging time. (If this is no longer a problem, please rejoice at the march of progress and refactor/delete this comment.)
Most modern development environments will happily demangle the names for you.
Now that most of the implementation issues are worked out (a process that took quite a few years from the addition of templates to the AnnotatedReferenceManual? to most compilers doing them right), they are actually one of the cooler features of CeePlusPlus.