2021-10-04

What is wrong with C++


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.

1 comment:

  1. Many of these things are out of date.

    "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

    ReplyDelete