Some people, when presented with a problem, say "I know, I'll use C++ and templates!". They then are faced with an unbounded number of problems.
The fact that this is possible, during compile time, is cause for open weeping.
EDIT:
Note that this was not done in an ugly or even unreasonable way: the author clearly wrote code that is easy to follow, well-structured, and not abusing language features in any way. This is not a good thing.
Can you explain WHY an easy to follow, well-structured program that does not abuse language features is a bad thing? Even if it uses the functional language known as C++ templates to calculate a large amount of things at compile time? Heck, in this case, you could think of the compiler as a slow, purely functional, interpreter :)
EDIT: Note that I am not endorsing C++ or doing crazy things with templates. I tend to like C++ personally, but have also been finding the simplicity of C to be quite nice, and have worked with a decent number of other languages (popular and academic, with varying degrees of time spent from professional to a small side project). I'm merely curious about why using the template system to calculate things (even if they're large, complicated things) is immediately declared as "bad" if the code is well-written, rather than something that requires 6 months of study to really understand.
The only super legit argument I've heard in favor of _not_ using templates or avoiding them in general is because of the code generation bloat - which is an issue on the consoles I worked on (every K counted on our wii app - we really did run down to the meg in memory usages). That and not all compilers at the time (even as recent as 2007 when I was working on wii) would compile templates well. Now it's much more mature and more widely supported (at least on x86).
> The only super legit argument I've heard in favor of _not_ using templates or avoiding them in general is because of the code generation bloat
And even then, it's important to recognize that bloat is a relative measure. If you use just one instantiation of a template, you're not paying for multiple versions of the code.
If, on the other hand, you use multiple instantiations, the code will be bloated compared to, say, a single type-erased version— but will not be any bigger than if you had written several "instantiations" of the same code by hand. There's a tradeoff to be made, too, since a statically-typed version of a function will probably be faster than a type-erased version.
Anyway, w.r.t. bloat, templates aren't the problem; static polymorphism is (can be). Templates are just a way of implementing static polymorphism.
Indeed, if you use one expansion of a template, then the bloat is just that of whatever code the template generates, which would still be there if you wrote the same inline code by hand. If that code is inline code, you get the same inline bloat.
C++ compilers handled templates very well for me in the late 1990's.
I wrote template headers in such a way that they could be included into a common .cc file, where template instantiations could be placed. By defining some #define symbol prior to including a template header, I would force it to supply the definitions. Without the #define, no other translation unit had access to the template bodies, and so generating bloat couldn't happen. (Another way is to have two headers: foo.h for the template declaration and foo-impl.h for the bodies of the template functions: foo-impl.h is only included in the translation unit that instantiates.)
If the templates for different types are instantiated in the same translation unit, that maximizes the opportunity that the code for identical expansions can be merged (if the compiler supports it). But more importantly, you control the bloat through the discipline of having a catalog of explicit expansions.
I avoided code bloat not only by using the above trick, but simply by writing light-weight templates. Templates cause particular bloat when they are inlined, because inline functions cause bloat, and inline templates generate them. The solution: don't put anything into the body of a template function that you wouldn't put into an inline function. Secondly, make the tiny inline template function rely only on non-template pieces to do its job. Sometimes designing this way creates a type-fragile implementation. However, if that code is used properly through the templates (and only through the templates), then it is safe.
Perhaps C++ compilers handle templates better now in the sense of managing the expansion more transparently and merging some of the bloat; but manual techniques have worked well for a long time.
I have a somewhat cautious relationship with template meta-programming, and hope to avoid it as often as I can. My typical use cases are such that I can solve my programming tasks without them.
However, that I can do without, doesn't mean that this is "not a good thing" to have as part of the language. The flexibility of C++, including what comes with the help of the preprocessor and meta-programming is part of what powers many of the features you use. Even if you yourself are not using those features, you are relying on libraries that do.
Even if your use case somehow didn't need this or anything that comes as a result, most use cases do. Which makes a good enough reason for it to be an excellent feature of the language.
You make a great many assumptions about the libraries that I use, and how I use them. :)
There are people that use templates to their full ability, and do not bat an eye at the resulting template errors or weird code issues.
Most of the times I see people using templates I can't help but wonder "Why the heck aren't you using a language that fits your problem better?".
They're cool features, sure, but notice that the days of C++ as a practical get-shit-done language are pretty much over. There's not really anything I'd consider C++ best or even second-best at if you can use other languages.
I'm not sure why you say I make assumptions as to what libraries you use. In fact, I thought I made it apparent that I made no such assumptions, given that I stated both possibilities: 1) You use libraries that are powered by meta-programming (making it good for you, ergo good that it is part of the language). 2) You don't use libraries powered by meta-programming (doesn't matter, a huge c++ user base do, ergo good that it is part of the language).
If you belong to either of 1) or 2), it doesn't matter whether or not this feature is possible, you can choose not to use the libraries, and you can choose not to use meta-programming features.
Could you share an argument as to why you feel a language shouldn't have features that you don't have to use?
If you don't use STL, boost, QT, or pretty much any C++ library I can think of... do you write everything from scratch?
As for when C++ is "best" or "second-best", these kind of questions tend to lead to opinion-based arguing, rather than constructive discussion. I'm definitely not interest in the former, so I'll just give you the general objective consensus of the programming world: C and C++ are used when performance matters. C++ allows more abstraction without a real runtime cost.
So, framing the question as "a language shouldn't have features that you don't have to use" is kind of obfuscating the issue. The answer to that, for example, is of course not--as the Python folks are finding out (or celebrating, depending on how you feel about that way of thinking).
The problem is that the vast majority of languages have some features that you don't use, and even if others use them then things still generally work out okay--you can hide it away.
C++, via operator overloading, exceptions, backwards compatibility with C and its problems, templates, function overloading, and all manner of other things, is simply too large to be trusted. I assert that it is so difficult as to be practically impossible to ensure that, if you rely on third-party code outside of your direct control or the language spec, you are writing safe, performant, bug-free, and maintainable C++ code. C is magnitudes simpler, and people still manage to fuck that up.
Everyone bandies about the performance of C++ and the whole only-pay-for-what-you-use aspects of it, but in the fast majority of cases that's simply not important from a business or project standpoint. If you're writing numerical code, for example, why not just use the hyper-optimized compilers available for Fortran? If you're writing tight embedded control code, why not just use assembly?
Sure, I've had a friend that worked on the CMS at Cern and they used some unholy pile of C++ dating back 20 years and that worked well. I've known a bunch of people doing bioinformatics and they all write/copy/paste shitty C++ and get faster results than their semi-legible Python or MATLAB.
That said, all of those use cases are academic, which is maybe the last place where performance even matters (arguable in and of itself). You might claim "but but but games!" and then you'd be wrong again, because a great number of games are written using super-slow scripting engines and terrible C++ codebases. Mike Acton, giving a talk at a conference this year, pointed out that there was no compelling reason to use C++ over C because the OOP features fall on their face in a high-performance environment.
It's just a bad language. It was useful once, it's occasionally useful now (if you must, which you usually don't), but we really should just move on to new things.
Its OOP features are poorly thought-out, its performance with the standard library is pretty bad without modification for certain use cases, its learning curve is absurd, its growth is unbounded. Just let the thing die.
To answer your question about rewriting things:
We did write a lot of things from scratch, and spent years battle-hardening them, because we didn't want to deal with the (at that time horrid) development overhead and philosophical issues of Boost. STL was fine until it wasn't due to some cross-platform issues. QT/POCO are cool in their own right, but didn't match our use case.
The fact that this is possible is super awesome. C++ has a lot of features, templates being one of them, which are great tools for library developers. For the most part, if you're an application developer you never have to deal with templates other than using what has already been written by people smarter than you.
So I don't have to know C++ just templates and I can get all the speed of it and functional features too? I would think more people would do this. I try to stay away from C++ because of a situations where small typos are not only still valid, but make the software behave in ways that I don't want and can't easily trap.
15 comments
[ 3.1 ms ] story [ 44.7 ms ] threadThe fact that this is possible, during compile time, is cause for open weeping.
EDIT:
Note that this was not done in an ugly or even unreasonable way: the author clearly wrote code that is easy to follow, well-structured, and not abusing language features in any way. This is not a good thing.
EDIT: Note that I am not endorsing C++ or doing crazy things with templates. I tend to like C++ personally, but have also been finding the simplicity of C to be quite nice, and have worked with a decent number of other languages (popular and academic, with varying degrees of time spent from professional to a small side project). I'm merely curious about why using the template system to calculate things (even if they're large, complicated things) is immediately declared as "bad" if the code is well-written, rather than something that requires 6 months of study to really understand.
And even then, it's important to recognize that bloat is a relative measure. If you use just one instantiation of a template, you're not paying for multiple versions of the code.
If, on the other hand, you use multiple instantiations, the code will be bloated compared to, say, a single type-erased version— but will not be any bigger than if you had written several "instantiations" of the same code by hand. There's a tradeoff to be made, too, since a statically-typed version of a function will probably be faster than a type-erased version.
Anyway, w.r.t. bloat, templates aren't the problem; static polymorphism is (can be). Templates are just a way of implementing static polymorphism.
I wrote template headers in such a way that they could be included into a common .cc file, where template instantiations could be placed. By defining some #define symbol prior to including a template header, I would force it to supply the definitions. Without the #define, no other translation unit had access to the template bodies, and so generating bloat couldn't happen. (Another way is to have two headers: foo.h for the template declaration and foo-impl.h for the bodies of the template functions: foo-impl.h is only included in the translation unit that instantiates.)
If the templates for different types are instantiated in the same translation unit, that maximizes the opportunity that the code for identical expansions can be merged (if the compiler supports it). But more importantly, you control the bloat through the discipline of having a catalog of explicit expansions.
I avoided code bloat not only by using the above trick, but simply by writing light-weight templates. Templates cause particular bloat when they are inlined, because inline functions cause bloat, and inline templates generate them. The solution: don't put anything into the body of a template function that you wouldn't put into an inline function. Secondly, make the tiny inline template function rely only on non-template pieces to do its job. Sometimes designing this way creates a type-fragile implementation. However, if that code is used properly through the templates (and only through the templates), then it is safe.
Perhaps C++ compilers handle templates better now in the sense of managing the expansion more transparently and merging some of the bloat; but manual techniques have worked well for a long time.
However, that I can do without, doesn't mean that this is "not a good thing" to have as part of the language. The flexibility of C++, including what comes with the help of the preprocessor and meta-programming is part of what powers many of the features you use. Even if you yourself are not using those features, you are relying on libraries that do.
Even if your use case somehow didn't need this or anything that comes as a result, most use cases do. Which makes a good enough reason for it to be an excellent feature of the language.
This is a good thing.
There are people that use templates to their full ability, and do not bat an eye at the resulting template errors or weird code issues.
Most of the times I see people using templates I can't help but wonder "Why the heck aren't you using a language that fits your problem better?".
They're cool features, sure, but notice that the days of C++ as a practical get-shit-done language are pretty much over. There's not really anything I'd consider C++ best or even second-best at if you can use other languages.
If you belong to either of 1) or 2), it doesn't matter whether or not this feature is possible, you can choose not to use the libraries, and you can choose not to use meta-programming features.
Could you share an argument as to why you feel a language shouldn't have features that you don't have to use?
If you don't use STL, boost, QT, or pretty much any C++ library I can think of... do you write everything from scratch?
As for when C++ is "best" or "second-best", these kind of questions tend to lead to opinion-based arguing, rather than constructive discussion. I'm definitely not interest in the former, so I'll just give you the general objective consensus of the programming world: C and C++ are used when performance matters. C++ allows more abstraction without a real runtime cost.
A good read: http://programmers.stackexchange.com/questions/29109/is-ther...
The problem is that the vast majority of languages have some features that you don't use, and even if others use them then things still generally work out okay--you can hide it away.
C++, via operator overloading, exceptions, backwards compatibility with C and its problems, templates, function overloading, and all manner of other things, is simply too large to be trusted. I assert that it is so difficult as to be practically impossible to ensure that, if you rely on third-party code outside of your direct control or the language spec, you are writing safe, performant, bug-free, and maintainable C++ code. C is magnitudes simpler, and people still manage to fuck that up.
Everyone bandies about the performance of C++ and the whole only-pay-for-what-you-use aspects of it, but in the fast majority of cases that's simply not important from a business or project standpoint. If you're writing numerical code, for example, why not just use the hyper-optimized compilers available for Fortran? If you're writing tight embedded control code, why not just use assembly?
Sure, I've had a friend that worked on the CMS at Cern and they used some unholy pile of C++ dating back 20 years and that worked well. I've known a bunch of people doing bioinformatics and they all write/copy/paste shitty C++ and get faster results than their semi-legible Python or MATLAB.
That said, all of those use cases are academic, which is maybe the last place where performance even matters (arguable in and of itself). You might claim "but but but games!" and then you'd be wrong again, because a great number of games are written using super-slow scripting engines and terrible C++ codebases. Mike Acton, giving a talk at a conference this year, pointed out that there was no compelling reason to use C++ over C because the OOP features fall on their face in a high-performance environment.
It's just a bad language. It was useful once, it's occasionally useful now (if you must, which you usually don't), but we really should just move on to new things.
Its OOP features are poorly thought-out, its performance with the standard library is pretty bad without modification for certain use cases, its learning curve is absurd, its growth is unbounded. Just let the thing die.
To answer your question about rewriting things:
We did write a lot of things from scratch, and spent years battle-hardening them, because we didn't want to deal with the (at that time horrid) development overhead and philosophical issues of Boost. STL was fine until it wasn't due to some cross-platform issues. QT/POCO are cool in their own right, but didn't match our use case.
I don't mean c++ isn't hard, I'm just saying it's not the only language where small typos can make everything explode.
Took me a while to compile (gcc 4.8.3 on cygwin64, had to add -std=c++11 -fpermissive)