Why C++ sails, while the Vasa sank
This article is a precis of a very interesting talk by Scott Meyers, and is written for those, who don’t have 70 minutes to listen to the full talk, but can spend 7 minutes to read the main points.
Some people do not program in C++, but they have heard about it, and they tend to think “Why would anyone use this language?” But there are people, who program in C++, and they sometimes ask themselves “Why am I using this language?”
There must be a reason, why people program in C++. To understand this, let’s go back to the beginning of the 90-s, when C++ was undergoing standardization. There was an enormous number of standardization proposals, and there were so many of them, that Jim Waldo, being on the standardization committee said: “Every extension proposal should be required to be accompanied by a kidney. People would submit only serious proposals, and nobody would submit more than two.”
If all the proposals had been accepted, the language would have been too complicated, and Bjarne Stroustrup said “Remember the Vasa!” Those not from Sweden had no idea what he was talking about. Vasa was a huge Swedish battleship, commissioned in 1625. The main principle of the construction was “Why don’t we add one more feature to this ship?” Many of the features were the King’s demand, namely, he approved the dimensions of the ship. Vasa also carried a lot of decorations and was heavily armed, because no one could refuse the King’s will. As a result, Vasa sank in her maiden voyage, hardly making her way out of the harbor.
Let’s have a look at C++. Is it ‘heavily armed’ with features? At first sight, it definitely looks that way:
Let’s have a look at this:
It looks clear – function “f” is invoked on “x”. And “f” can mean a function, or a function pointer, or a function reference. It can be an object of a class overloading operator (). Or, it can be an object implicitly convertible to one of the above. Or it can be an overloaded function. Or a name of a template or template specialization. Or simultaneously several of the things mentioned above.
It becomes clear why people consider C++ a complicated language. It looks as all of the abovementioned points to drastic faults in language design, as it is too complicated.
But if we look at it from another point of view, considering the number of vacancies for developers in different languages, the amount of code written in a language in open source projects, the number of search queries, etc., we will find that statistically C++ has been the 2nd-4th popular language in the world for the last 25 years.
C++ is the second language in the world according to the amount of code written in open source projects (12%) and the popularity grows every year.
Therefore, C++ must have done something right. Somehow it sails. Let’s see why it is so.
Compatibility with C
A code written in C can be used in C++. Take a C editor, or IDE, or a linker, a debugger, and you can use them in C++ as they are or with minimum adjustment. A programmer, who programs in C, already knows many features of C++. Learning OOP, STL and, maybe, some other things will enable him or her to program in C++. This was extremely important in the 90s and in the beginning of the 2000s. C remains the most popular language for code-writing today.
The most important feature of C++
What would you call the most important feature of C++? (audience replies: “curly braces”, “templates”). That’s destructors. Destructors made RAII possible. Destructors have drastically reduced the complexity of concepts used in programming. Destructors made possible undoing memory allocation, mutex acquisition, opening files, network connection. Destructors save us from the condition branches, unnecessary goto.
There is a little crater on Mars caused by crash of a research spacecraft. It was not supposed to crash, but it did. It happened because in one part of the code a programmer used metric units, and in another part of the code another programmer used English units. And it turned out that a kilogram does not equal a pound.
C++ templates made it possible to write abstract code, algorithms, functions and classes, which can be specified during compilation as definite types. This is a huge step forward. And there is no run-time cost!
Functions, methods and operators can be overloaded. This can make the code simpler and more eloquent. Overloading function call operator became the basis for lambdas in C++11, and lambdas are very useful.
Language for library writing
C++ was developed as a language not so much for application development as for writing libraries. It was thought that creation of multiple good libraries will allow developing good applications. It is safe to say that there are plenty of C++ libraries today, which means that the idea was a successful one.
Multi-paradigm character of C++
Procedural programming, object-oriented programming, template meta-programming are all possible with C++, as well as “unsafe” programming with pointers and assembler insertions, and a combination of different concepts. Even functional programming becomes, to some extent, possible with the new C++ standards.
The best language for demanding systems applications
C++ may not be the best language in the world, but currently it is the best language for demanding systems applications, in other words, – programming to satisfy certain constrains. The constrain may be that the object domain is unknown, or that the system should run fast, or that it should use minimum CPU, or communicate with a strange source code or hardware, etc. Choosing C++ in a situation with one of the mentioned or some other constrain, you have much confidence that you will not fail the project because the language you chose cannot solve the task.
You don’t pay for what you don’t use
One of the basic principles of C++: if something can be calculated during compilation it is done during compilation. The code which is not used is not activated. A program does only those instructions, which you’ve written, and it does them in the order you’ve specified. Nothing else, everything is transparent. Such things are very important in systems programming.
Designed for very wide platform availability
This is another feature of compatibility with C. A program in C++ is pretty much clear in an assembler and very often you can understand the set of assembler instructions produced from a code in C++. Consequently, you can write programs for any platforms. Moreover, C/C++ are the only languages to be used with some platforms.
Source code written in the early 90s in the first standards of C++ can be compiled today under C++14, and it will compile, and it will, probably, function it has to. There are few places where it might change, but they are not many and they are well-known. In such a way a company has guarantees that by investing into an asset written in C++ today it can be sure that the code will continue working in 10 or 20 years and therefore the money won’t be lost.
C++ is often blamed for producing too complex of a code. It would be correct to say that, if you want to, you can write a complex source code in C++. And describing a code in C++ is complicated too. Let’s have a look at this:
std::cout << x;
Oh, my God! It has a namespace, a stream, a template (implicitly instantiated), a class object (inherited from another class) and overloading operators. But have a look at the code once again. Is it really too confusing to understand? Do you really think about those formidable terms I have mentioned, when you read the code? You don’t. Because the complexity is hidden and you do not notice it.
Language of last resort
People, who decide to program in C++, usually know a bunch of other languages – script languages, managed languages, functional languages. And when it is possible to use them, they do. But sometimes the task is too complex, the demands are high, and the risks are huge. And that’s when people resort to C++. It is a complicated but a very powerful tool for complex and large-scale projects. That’s, by the way, one of the reasons why programming in C++ and a source code written in C++ are considered complicated –average complexity of tasks solved with C++ is higher than that solved with other programming languages. It would be naïve to expect a solution for a complicated problem with a minimalist source code.
Language for those who loves complexity
It is easy with C++ to shoot yourself in the leg. And there are many ways to do it. But it is an advantage for some. A possibility to shoot yourself in the leg presupposes an ability to shoot anywhere, in any way you like and as much as you like. It is true, though, that the results may be terrible. But the power of the language is truly amazing.
C++ Standard is becoming bigger and… simpler
In 1990 C++ Standard was 400 pages long, in 1998 – 700 pages, and in 2011 – 1300 pages. You often hear that “the language is becoming more complicated”. But it is not. It is true that new notions and features are introduced, but the majority of them aims at simplifying the code, not complicating it. Remember how you had to use iterators on every element of a vector in C++98? C++11 has ‘range-based for’ and ‘auto’, which make it possible to write one line of a code where we used to have five. Lambdas made it possible to exclude the unnecessary classes and methods from the code. The developers of the Standard have to think over and write much more text. But from a programmer’s perspective things got simpler.