First of all, this is an opinion piece. If you don’t agree, fine. Regardless of your opinion, comment if you must, but remember, comments that are completely unconstructive will not be approved.
Now, on to the point of this rant. C++ sucks. It is, perhaps, tied for the worst language design in the history of computing. Here is why.
First, C++ builds on C, but instead of outright replacing features of C that C++ provided alternatives for, it simply bolted additional aspects onto the existing C language. Thus, instead of having only one keyword to make an aggregate type as in C, you now have two with slightly different semantics. Instead of pointers, you have references which are almost but not quite pointers, and also still pointers. Instead of disallowing the C standard library and providing its own, you have the C++ standard library but you can also use the entire C standard library. Indeed, the end result is basically all the festering badness of C combined with a poorly conceived and implemented object model.
Let me go back to early C++ before the standards committees got their hooks into it. It was a simple enough language which had useful features compared to C. It added operator overloading, function overloading, and objects. In all, it seemed a fairly decent expansion on C. There was only one problem. There was no way to handle error conditions in constructors or destructors, making it impossible to properly handle resource acquisition and release. Why it wasn’t possible to return an error from constructors and destructors does make some sense given their actual usage in many circumstances. It is also not an insurmountable problem, after all, since careful programming can avoid most problems in the destructor and a “factory” method can solve the constructor problem.
Even early C++ showed the beginnings of a horribleness, though. The standard library, particularly the iostream stuff, demonstrates a complete lack of understanding of real world I/O problems. Rather than simply encapsulating something like the C stdio subsystem, instead it provided a ridiculously baroque pile of crap that could only be used effectively for very basic text I/O. While stdio sucks somewhat for structured input, iostream sucks more. Instead of a relatively compact scheme like the printf() family of functions for formatted text output, you have to implement a wordy chain of mutators and output values that does little more than obfuscate just what you are attempting to output in the first place. Instead of being able to scan a format string and compare it with a relatively short list of formatting codes and explanations, you have to somehow divine the initial state of the output stream and then track potentially dozens of state shifting objects just to work out how numbers are going to be formatted. And all of this is using overloaded bit shift operators (apparently because hardly anybody does bit shifting).
C++ apologists and fans will claim that the C++ way is more object oriented. I clearly have no understanding that the C++ way is the one I really want. To them I point out that I learned C++ first and the C. Yes, that’s right. I learned the C++ way first. Then I found printf() and friends and I was enlightened.
Fortunately, it is perfectly possible to completely ignore the iostream bullshit and go straight to using stdio. Consider that stdio gives pretty much everything that iostream attempts to provide. The FILE pointer is basically an object with methods on it (all the stdio functions that operate on FILE pointers) including constructors (fopen() among others) and a destructor (fclose()). Used according to the defined interface, this is a perfect implementation of object orientation. There is no reason that stdio could not have provided a means to attach arbitrary user defined schemes into the FILE object or attach additional format specifiers to the printf() family functions.
Had C++ stopped there, it would have been bad enough, but not horrible. Instead, additional features were slowly grafted onto the language. One such feature was templates, which were conceived in the absence of any inkling of how to properly implement them. Sure, the notion looks brilliant on paper. Let’s write a generic set of code for, say, a linked list, and have the compiler generate specific code for the contents of the list. And this works brilliantly in a single file compilation. But what happens if the template is instantiated in several different files in the same project? Oops! Suddenly you have linker errors from multiply defined symbols! This was such a problem that I remember needing to use “-fno-implicit-templates” and have a separate file that instantiated all of the templates needed for a project. That was bad. It actually needed a thing called “weak symbols” or something like that and special support from the linker to make it work properly.
Even templates were not horrible on the surface except for the terrible syntax selected for them. (< and > anyone? Duh! Obviously a bad idea!) They should have had a distinct syntax using distinct tokens. But that would have potentially broken previous code or something like that. That just wouldn’t do. Instead of inventing a new syntax with new tokens and calling it C++ Version 2 or something, they overloaded existing tokens.
At around the same time came namespaces which seem like a good idea, and, in fact, are probably one of the few features of modern C++ that is not a horrible festering pile of crap. At the very least, they allow one to avoid name conflicts between different packages. Even the choice to use the same scope resolution operator (::) is not a horrible one. I don’t actually have an issue with this one save that it changes the semantics of the language at a fairly late date, but that’s even minor.
The biggest thing that causes no end to trouble is exceptions which were ostensibly a solution to the fact that constructors and destructors cannot report errors. But it actually solves the wrong problem there. In fact, exceptions are not necessarily a bad idea when used judiciously (which they aren’t), but the execution in C++ is terrible as it interacts horribly with other language constructs, notably object construction and destruction when resource exhaustion is involved and used by the exception object. Why it was deemed a good idea to be able to throw an arbitrary object as an exception mystifies me – it makes no sense whatsoever. There should have been strict restrictions on what was throwable. Leaving aside the horrible coding style that exceptions encourage, which is hardly the language’s fault, the execution in C++ makes it nearly impossible to do them right.
As C++ developed over the years, it became clear that the ivory tower academics (read idiots who do no real work) had increasing influence, attempting to turn C++ into a poster child for “abstract data types” and all that rot that they teach in comp sci programs. The absolute worst aspect of modern C++ is the standard template library (STL) which epitomizes the academic ideal of data structure design. What that means is it is horribly inefficient, excessively verbose, and difficult to do any real work using it. Worst of all, it attempts to implement a series of data types that make absolutely no sense in C++ or which cannot be sensibly implemented, and these standard templates often have a convoluted incestuous relationship. This is in addition to the non-template standard types which suffer from all the same problems. The thing all this stuff forgets is that there is no one size fits all solution to any non-trivial data structure, and that often holds true for trivial ones too.
Of course, I can simply ignore the standard template library and the standard data types, for the most part, in my own code, but as soon as I attempt to interface with a library or code written by someone else, I have no alternative but to deal with that crap. The problem is further exacerbated by the existance of such “helpful” libraries as Boost.
In short, C++ is a shining example of design by academic committee. (An academic committee is orders of magnitude worse than an plain committee.) This is the absolute worse way to design a programming language. Period. And this is why C++ is bad, and also why I do everything I can to avoid using it at all. I find object orientation in plain C to be far more pleasant than modern C++. (Yes, you can do object orientation in C with relatively little overhead, and with much more flexibility than in C++. All it takes is a bit of discipline, and that is required to do things right in C++ too.)
Anyway, that’s it for my rant. You may or may not agree. That is your perogative. There is plenty on the internet lambasting C++ and plenty praising it. I invite you to read both sides with an open mind and make your own determination. Consider actual real world situations with real code to understand the issue. Examples presented in literature on both sides are contrived to support the point being made. Examine the examples and understand how they work and why. That can be as enlightening as the prose in any argument.
The job of a language is to produce words precisely. You think about something, then you speak it out, or write it down, the words are built upon only 26 alphabets, but from there I see “your” thoughts. A language is like a piano, it has only 88 keys, but it produces melody precisely. A language is like pigments, maybe they do not have the color we want, but when we mix them , one may be produceed, instead of inventing a new type of pigment.
So, when it comes to programming, C is good, because it trusts us, allows us to express “our” thoughts, or do the “stupid things”. It does what we want, precisely. And we build complex things from simple things.
I’m not entirely clear what you’re trying to say, here, but I do like the way you’re saying it. Particularly, I think you mean “26 letters” rather than “26 alphabets”. It sounds like you might be agreeing with me after a fashion with your comment about how C is good.
This is not targeted at you, beorht, but I just need to clarify for the interwebs that C is not C++ and that C++ is not C. They are different languages. I wish I didn’t need to say that but there are a great many commentators out there that write “C” when they mean “C++”.
I am really happy to read such an opinion. I totally agree with you. I also think that C++ is now diven by kind of “academic” people. Two more inputs:
First the worst with template is that there is no definition/checking of the protocol like with classical inheritance interface. In interface you define asbtract functions that have to be redefined. If these functions are not redefined in implementation class (ie derivation of the interface) then the compiler complies and the message is clear. With Template, if a function is missing, then you will get an error messagre within the Template code which is not yours! So this is very annoying.
Second, people for the committee try to introduce more functional stuff into classical language, because academics people are fan of that. However, nobody uses it in the real world, because: it is too much difficult to read it six month after writing it and it is very difficult to modify it where as adding a test into a loop is simple.
The main issue is that some parts if the language are alsmost impossible to understand for C++ expert and I think that we will see a big fight between C++ users.
You left out the best part: Overloading of assignment operators! Want the equals sign (=) to mean something else? C++ gives you the power to do that! Which has the side effect of turning your code into something that’s not really like C++ anymore.