This is part of a series of posts in which I am documenting what is wrong with certain popular programming languages that I am (more or less) familiar with. The aim of these posts is to support a future post in which I will be describing what the ideal programming language would look like for me.
I will be amending and revising these texts over time.
(Useful pre-reading: About these papers)
What is wrong with C++:
- Multiple inheritance.
- Incredibly complex syntax. (Would you like some const with your const?)
- Cumbersome syntax. (Member variables cannot be initialized at the point of declaration.)
- Requires splitting the code into header files and implementation files.
- The ability to use incredibly complex constructs (pointer to pointer to pointer) leads to code that is understood only by the original author, only within a short time after writing it. After that short period of time has elapsed, there exists nobody in the entire universe who understands that code.
- The ability to freely manipulate pointers often leads to illegal memory accesses.
- Manual memory management often results in dangling pointers or memory leaks.
- Lack of generic types.
- Templates are much more cumbersome to write than generic types.
- Templates do not promote abstraction.
- Templates result in a larger executable, which at runtime translates to a larger working set, which translates to reduced performance.
- Lack of C#-style properties. (Though perhaps some of their functionality can be achieved by operator overloading?)
- Intentionally undefined behavior.
- Is essentially a form of error-hiding, and often results in code that works by coincidence but will horribly break under slightly different circumstances.
- No reflection.
- RTTI is a very poor excuse for a substitute to reflection.
- The built-in (stl) collection model is lame:
- Arcane nomenclature (whoever thought you can push into a vector!)
- No collection class hierarchy: each collection class is a snowflake. They do not, for example, all inherit from some `Iterable` common base class.
- No abstraction: each collection class has its very own snowflake iterator class.
- The preprocessor hinders static analysis and removes any guarantees about the semantics of the source code.
- Gives the programmer a false sense of control over code generation.
- Thinking both at the problem-solving level and at the code generation level results in severe cognitive overhead.
- At the end of the day, this is all an illusion, as the optimizer will generally do things quite differently from what the programmer imagined.
- The "you don't pay for what you did not order" dogma prevents a multitude of extremely useful error checks (such as array index out of range) and safeguards (such as guaranteed zero values for non-explicitly initialized members and array elements.)
- Curly braces.
Note: the above list of disadvantages is kind of short, because my C++ is a bit rusty.
Feedback is more than welcome: you'd be doing me a favor. However, be aware that blogger sometimes eats comments, so be sure to save your text before submitting it. If blogger eats your comment, please e-mail it to me.
Many of these things are out of date.
ReplyDelete"Member variables cannot be initialized at the point of declaration." <- They can since C++11
"Requires splitting the code into header files and implementation files." <- Not strictly true, pretty much everything can be in a header file since C++17
"No collection class hierarchy" "No abstraction" <- Since C++11 for ( type elem : range ) iteration is applicable to any range
"The preprocessor hinders static analysis and removes any guarantees about the semantics of the source code." <- Static analysers can preprocess too
"a multitude of extremely useful error checks (such as array index out of range) and safeguards (such as guaranteed trap values for non-explicitly initialized members and array elements.)" <- undefined behaviour means debug builds are allowed to have these things, and checked equivalents are also available
Others are fixable with a style guide
"Manual memory management often results in dangling pointers or memory leaks." <- Memory management is done by library code.
"Templates are much more cumbersome to write than generic types." <- Only when you declare a class template's member functions out-of-line.
And in some cases I'd say you are flat wrong
"Templates do not promote abstraction" <- You can't add an interface to a class post-hoc, whereas you can have a class that models a type constraint post-hoc