1. 21
  1.  

  2. 15

    This is a really nice post, but the author chose the wrong headline/title. It should be, “The problem with C++”.

    I am not being snarky. The entire article is about the C++ standards process, C++ language complexity, and the C++ community’s inability to understand the C community as anything more than legacy code.

    But meanwhile, new code continues to be written in C every day, experienced programmers (like me) continue to prefer C over C++ for systems code, and C support has never been stronger with gcc and clang as multi-platform C compilers. Indeed, the biggest “problem” with C (which, by all measures, is one of the world’s most successful languages) is the existence of C++!

    C++, meanwhile, is an increasingly niche choice for high-level and/or OO programming in all domains except for gaming/3D.

    1. 6

      But meanwhile, new code continues to be written in C every day, experienced programmers (like me) continue to prefer C over C++ for systems code

      I’d have said the same thing a decade ago, but C++11 changed the landscape and there’s no comparison between C11 and C++17. Systems code is all about data structures and templates make it far easier to write type-safe data structures than anything in C. They also make it easy to abstract the implementation away behind an interface so that you can experiment with different implementations with a self-contained change.

      C11’s stdatomic.h is a mess. They got some things fundamentally wrong, such as defining an _Atomic qualifier but then making all of the functions in stdatomic.h take volatile T* and not _Atomic(T) * parameters. C’s _Atomic is allowed to take any structure, but then requires a call to a helper library to implement that. The volatile parameters in the stdatomic.h interfaces (and the requirement to cast to them) mean that you can’t define a C ABI where sizeof(T) and sizeof(_Atomic(T)) differ, so you can’t store a lock word inline in the larger types. In C++, std::atomic is a template and the only reason that you can’t store a lock word inline for larger types is the desire for C compatibility: std::atomic<T> should be ABI-compatible with _Atomic(T).

      C11 thread-local storage is also a mess: there’s no standard way of associating a cleanup routine with a TLS variable, so you end up in a

      A language that makes atomics painful to use does not, in 2020, qualify in my mind as a great systems programming language.

      We have recently written a memory allocator and a language runtime in C++17. These are pretty much archetypal systems programming language tasks.

      The memory allocator happily outperforms jemalloc (written in C) and produces a significantly smaller binary. Compare the clean self-contained (yet always inlined) platform abstraction layer in our allocator to the mess of #ifdefs in most C codebases. A few PALs have different functionality (not all underlying operating systems support providing very strongly aligned allocations, for example), but we can use constexpr if to gate those things on features that the PAL exports and only compile the necessary code paths, without needing any platform-specific #ifdefs anywhere outside the PAL. Not that, because this is low-level systems code, we adopt a C++ style that does not depend on the C++ runtime at all: no vtables, no RTTI, no exceptions. We don’t depend on anything other than a basic C environment, yet get a very rich set of benefits relative to using C directly, including the kind of aggressive compile-time specialisation that lets us trim our fast paths down to a handful of instructions.

      1. 3

        I’d have said the same thing a decade ago

        Me too. I write C++ professionally, and the common thread I see is that people still think of C++98 when they think of C++.

        no vtables, no RTTI, no exceptions

        Even when still using the C++ runtime, no RTTI, no exceptions and few (if any) virtual methods is extremely common in my experience. I can’t remember the last time I used any of these.

      2. 3

        But meanwhile, new code continues to be written in C every day … C++, meanwhile, is an increasingly niche choice

        I’m not sure that’s necessarily true. The Tiobe index - https://www.tiobe.com/tiobe-index/ - shows C as much more prevalent than C++, but also shows both as gaining popularity (which to me seems more likely a short term rather than long term trend in both cases). Another ranking (2018) on the other hand shows C++ is more active on Github: https://www.benfrederickson.com/ranking-programming-languages-by-github-users/

        Anecdotally: I use C++ at work, and that’s not in gaming/3D but in program analysis. It’s used for runtime speed and expressiveness.

        1. 4

          Fair. I didn’t mean “niche” as in “unpopular”. I meant “niche” as in “appealing to a highly specialized audience”. That is, from a 2020 vantage point, you only tend to choose C++ if you have special needs – it’s not as much of a “general purpose” language as we originally thought. For example, it was probably the right choice for clang & llvm, because compilers are big chunks of software that benefit from OOP, and the need for speed is real. But would you write a web app or command-line utility in C++ “by default” or “for programmer ergonomics” these days? Likely not.

          1. 3

            Why not for a command-line utility? If I have to handle character strings, I prefer C++ over C.

            1. 2

              I guess he meant that unless you need performance you will probably use eg. Python for CLI.

          2. 1

            TIOBE is not an indicator of what new software is being written in. It’s an indicator of what people are talking about.

            1. 2

              It seems likely that there is at least some level of correlation between those two things.

        2. 8

          Fundamentally I think C trusts developers while C++ trusts compilers. This is a massive difference that sharing the same native types or syntax for while loop cannot hide.

          I think this is a nice lens for viewing programming language decisions.

          1. 3

            As compilers are overcomplex pieces of software which can’t be trusted, this lens might favor C way too much.

            1. 2

              Just like brains are overly complex pieces of hardware / software which can’t be trusted.

          2. 4

            “But C is proudly a low-level language. A nicer assembly.”

            It’s very much not, though. Some C developers may see it that way, but compiler developers do not. There are various rules which shall not be broken in C without potentially dire consequences - the strict aliasing rule and the out-of-bounds array access are the two examples that spring most readily to mind; breaking these rules yields undefined behavior, and that’s nasty, potentially opening security holes.

            It’s long past the time when it was safe to view C as “a nicer assembly”.

            1. 1

              Some C developers may see it that way,

              Not some, virtually all.

              but compiler developers do not.

              Yes, and that’s a huge problem. The C language has gotten away from its users.