Was Linus Torvalds Right About C++ Being So Wrong?
Nerval's Lobster writes: Perhaps the most famous rant against C++ came from none other than Linus Torvalds in 2007. "C++ is a horrible language," he wrote, for starters. "It's made more horrible by the fact that a lot of substandard programmers use it, to the point where it's much much easier to generate total and utter crap with it." He's not alone: A lot of developers dislike how much C++ can do "behind the scenes" with STL and Boost, leading to potential instability and inefficiency. And yet there's still demand for C++ out there. Over at Dice, Jeff Cogswell argues that C++ doesn't deserve the hatred. "I've witnessed a lot of 'over-engineering' in my life, wherein people would write reusable classes with several layers of inheritance, even though the reusable class wasn't actually used more than once," he wrote. "But I would argue that's the exception, not the norm; when done right, generic programming and other high-level aspects of C++ can provide enormous benefits." Was Linus going overboard?
The problem with C++ is that it's way too easy to write write-only code, because the language has so many features that nobody but language experts understand all of them. So we all program in different dialects, and then scratch our heads when we read other peoples' code.
I always get halfway through a Nerval's Lobster summary before my anger/indignation/smug validation gives way to the sad realization that Dice has trolled me yet again.
Could we stop having Dice articles submitted by Nerval's Lobster? Why not fully disclose that the story was submitted by the corporate parent of Slashdot?
If you care about performance, the ability of C++ to "run on the iron" is a valuable tool to have in your arsenal. Add in inline assembler, and IF YOU KNOW WHAT YOU'RE DOING you can write blazing fast code in C++ and still provide a sensible code architecture.
There's no sense in blaming the language for the abuses developers have written -- you might as well indict English for the horrible spelling and grammar of many Americans...
If you know what you're doing, C++ is a terrific, powerful language suitable for a plethora of projects. On the other hand, if you don't know what you're doing, well, I guess there's Visual Basic or C#.
Bad programmers can produce bad code in any language, including one as well/thoroughly specified as Ada. The difference, though, is that what that code actually does is less subject to interpretation by the compiler.
I've observed that two Ada programmers will argue, "Is this program legal?" If the program is legal, they both -know- what the compiler will do (modulo the rare compiler/optimizer bug, which was usually caught through the stringent compiler validation.)
Two C++ programmers will argue, 'What will my compiler do with this code?"
A clickbait article about a flamebait rant, commented on by trolls.
God bless Slashdot.
I just looked through Nerval's Lobster's last 15 contributions. All were article submissions, Nerval's Lobster doesn't appear to comment on anything. Here's the list:
Every single one of them is from dice, though only a few of them actually make that explicit (the non-explicit ones are marked [Dice*]. A large fraction of them are related to human resources and hiring people, which I've marked [Hiring]. So its like Nerval's Lobster is using Slashdot as advertising and recruitment channel for Dice.
The average quality of these submissions was very low in my opinion - lots of vacuous pointy-haired-boss buzzword stuff. Very un-nerdy. How did these get through submission moderation? Were they even subjected to it?
C itself has so many pitfalls. For the best tour review the underhanded C contest. "features" like automatic concatenation of consecutive character strings means that if you leave out a comma in a list, the adjacent array element entries are concatenated rather than throwing a syntax error. That list will now not match the declared array size (one short, so there's a null or random pointer in the last element) but the compiler allows initialization listed mismatched to the array sizes. Character strings have to be declared one longer than the initialization string length (room for the unstated \0) but are accepted by the compiler if they don't giving an unbounded string length.
it's mind boggling to realize that
int (*int)[20];
int *int[20];
are different things.
the number of different ways an array argument in a function can be written makes code hard to grasp: is it a pointer, an array, a reference? many work alike but then fail in different ways.
The most common of all pitfalls and hard to read codes are the in-line initializations that pop up in function arguments and what not. this leads to classic blunder of writing = when you mean ==.
Perhaps the most insane thing is that If you declare an external function with the wrong prototype then any mismatch in the argument count leaves or takes something off the stack. Holy cow..... I mean what the hell? Why would any language ever ever ever let you leave a orphan argument on the stack, or worse pop one off that was not yours? This is very useful for the underhanded C folks however.
While I know there's little love for fortran, it's worth noting that none of those things is even possible in Fortran, so its an existence proof that there's not any necessity for those to exist and that it doesn't limit the power of the language to remove them. It's very fair to say that no simple typo will ever compile in fortran (yes very complicated offsetting typos can compile).
Some drink at the fountain of knowledge. Others just gargle.
You can argue about whether C++ is a horrible language (I lean toward "yes") in itself, but the libraries are what really push it over the edge. STL is hands down the worst collections framework I've ever encountered. Consider just a few examples of how you do some common operations with it, compared to doing the same things in Java and Python.
1. Check whether a string s ends with a suffix t.
Java: s.endsWith(t)
Python: s.endswith(t)
C++: s.rfind(t) == s.size()-t.size()
2. Check whether a collection c contains an element e.
Java: c.contains(e)
Python: e in c
C++: c.find(e) != c.end()
3. Split a string s into tokens based on whitespace.
Java: s.split() ... do you really want to know? Ok, check out http://stackoverflow.com/quest.... There you will find dozens of proposed solutions (many of them quite indecipherable), along with lots of debate about which one is best. The top voted solution has a comment on it (with several hundred votes) saying that it's a bad solution and you shouldn't use it.
Python: s.split()
C++:
Doing even really basic, common operations with STL requires way too much work and produces absurd, hard to read code.
"I'm too busy to research this and form an educated opinion, but I do have time to tell everyone my uninformed opinion."
Honestly, I find a random program written in C to be on average FAR less maintainable than one written in C++, usually because they end up reinventing the wheel about 50 times, usually poorly. The C program that I work on at work is one gigantic mass of poor wheel reinvention over and over again. Its impersonation of objects and inheritance (for sending message) is terrible, utterly terrible, it's almost impossible to build and send a message without messing up in some way due to all of the interconnected pointers. The macros they use to try to "simplify" it only make it worse. Some parts of the code have macros nested literally dozens of levels deep.
"Are you hungry? I haven't eaten since later this afternoon." -- Primer
Modern, properly designed C++ code is absolutely safer than C code. However, because C++ is a superset of C, you can obviously write code that's just as unsafe as C, simply by ignoring the best practices and writing "C with classes" (which many do). A lot of what you can do in C++ exists solely to provide backward compatibility, both with earlier versions of itself as well as with C.
C++ gives you the ability to create new types using objects, which you can operate on both through member functions as well as logical operator overloading (where it makes sense to do so). For instance, you could create a class for handling file paths (as opposed to using raw character pointers or arrays, or even C++ strings), and when that class is properly developed and debugged, you can then be confident that you no longer have to worry about accidentally creating a security vulnerability or introducing a crashing bug. Moreover, it can handle path-specific things, such as ensuring proper form when paths are concatenated. Even better, when compiled down, it's really no different than code written in C, since C++ still adheres to the "zero-overhead" principle for most features.
When people talk about C++'s "dangerous casts", they're almost universally taking about "C-style casts", which are discouraged in modern C++. Instead, you should use the more explicit casts, which either use static compile-time checking or even run-time checking as appropriate. Whenever you have to resort to a C-style cast in C++, you had better have a *very* good reasons (in many cases it's just a design failure). Nowadays, that also includes managing raw memory or raw pointers thanks to the addition of standardized smart pointers.
This is why C++ is almost universally used in the videogame industry (I work as a videogame programmer), because is strikes a reasonable balance between safety, advanced language features, and performance. It's also nicely compatible with C libraries, with which we often have to interface at the OS level, or when using 3rd party libraries. And finally, while "better" alternatives arguably do exist, C++ is also well supported and extremely ubiquitous across the industry. As the saying goes, "quantity can have a quality all it's own". This is important when trying to hire experienced developers, or looking on the web for solutions to a problem.
Irony: Agile development has too much intertia to be abandoned now.