Introduction
We’ve been hearing how small ubiquitous devices and vast web sites have reminded everyone that efficiency and performance really are important in code. All I can say is, yes. And you may also have been hearing that as a result, C++ is coming back! Um, why?
The conventional wisdom ten years ago was that size and speed didn’t matter much, since desktop hardware was so big, fast and underutilized. Instead, time to market, maintainability, integration, quality assurance— those were the things to worry about. Code bloat? Inefficient use of hardware resources? Not important.
As someone who did a fair amount of assembly-language programming on really small embedded systems in the 1980s, I could never quite swallow that argument. And because of the time I spent writing assembly-language, I deeply appreciate the C language.
C, not C++.
When I want the benefits of object-oriented development, including rich, powerful, well-architected libraries and all the convenient short-hands provided by templates, classes, overloading and inheritance, I use Python or C#. They are truly awesome, powerful, and fast! They produce very compact, portable programs (Python is especially portable, to all those outlying systems Microsoft has no time for…). They save you the trouble of managing memory. They make a lot of hard stuff magnificently easy. And if you don’t like them, there are so many others to choose from, like Java, JavaScript, Ruby, Eiffel, and so on and so Forth.
But if I’m trying to write the fastest, tightest code possible, for a driver or server application or library, I believe that C is still the right language: C, not C++. Why?
The thing about C is that it was designed specifically to balance the need for portability against the need in system programming to be able to understand exactly what your code is doing at a hardware level. It was and remains a brilliant abstraction of processor instructions. All those nasty preprocessor directives are an incredibly effective means of setting different contexts so the same code can run on diverse systems. The language itself is pleasantly terse (minimal typing), which is less important these days when our IDEs support code completion, but I’ll tell you, it used to matter a lot, and it’s elegant! My main point, though, is that C hits the perfect level of abstraction for system code. It’s high enough level that you can read a lot of it fast, and it’s low enough level that you can find out exactly what is happening at every step.
Why should you know what’s happening at every step? Isn’t encapsulation a beautiful thing? Not for system code. If you can afford not to care what your components are doing, use a really powerful scripting language. That’s often a good choice for mobile devices, too, because byte-code is a lot more compact than native code and is easily portable.
Now, the C++ aficionados will say, perhaps rightly, that for very large projects with multiple teams, C++ can facilitate inter-team communication. It’s more type-safe. You can spell out your contracts more clearly using classes and interfaces.
Well, you can do the same things in C, of course, just by taking care. Most of the shortcuts and short-hands of C++ are just that, and the simplicity of C makes you express your APIs in a very concrete way. C forces you to expose what you’re doing, where one of the objectives of a lot of C++ code is to obscure (encapsulate) it. And look, if you’re thinking about performance, you have to focus on two things:
q Am I doing things the most effective way (am I using the right algorithms)?
q Am I doing things as efficiently as possible (am I avoiding unnecessary steps in my implementation)?
The short-hands and shortcuts of C++ generally make both these factors harder to evaluate.
Also, transparency is particularly valuable in the open-source context, as opposed to the standard corporate model where source-code is kept secret. Even on very large system projects, I believe that the simple clarity of C code makes it the best choice. For instance, say what you will about Linus Torvald’s personality, he’s a good architect, and Linux remains clean and well factored. It would not be any easier to understand if it were written in C++, and it would likely be much messier under the hood.
Incidentally, I adore Linus’ famous rant on this subject in 2007 (http://harmful.cat-v.org/software/c++/linus). What a jerk, but he’s so right! And he is not alone in having problems with C++. Among its detractors are the likes of Niklaus Wirth ("C++ is an insult to the human brain"), Alan Kay ("I invented the term Object-Oriented, and I can tell you I did not have C++ in mind"), Bertrand Meyer ("There are only two things wrong with C++: the initial concept and the implementation," or “C++ is the only current language making COBOL look good”), and even Donald Knuth ("Whenever the C++ language designers had two competing ideas as to how they should solve some problem, they said, 'OK, we'll do them both'. So the language is too baroque for my taste").
Now, I know C++ programmers will passionately disagree. Bjarne is every bit as arrogant as Linus, and Microsoft is busy drumming up business for a “modern” C++. I’m just telling my own experience: object-orientation is good when I don’t have to care about what’s happening at the machine level. If I have to care, C is the language I choose. Still.