Why C++ sucks (2016.02 edition)

I see that there’s some interest around my “Day when I gave up on C++“. People on reddit discover this article of mine from time to time, and it’s somewhat boring to see the same things discussed over and over again.

To be honest, I don’t agree with my article, but I do agree with the points I’m making. I was very upset that day – it was yet another try to start a project when I had to work for two days for the basic setup only to see that things don’t work. After a set of frustrating cycles of try/find errors/search-for-solutions/try-again-with-something-else I just gave up on a project that is very dear to me. I don’t have the energy to fight with the language, even though I follow it closely. But it’s the same with advanced physics. Yes, neutrinos, bla bla bla, but does that make my car go faster? No? Ok,

I will just say one last thing about that article. It was written after I came to the conclusion that it was impossible to have graphics and a proper C++11 compiler working together. Not to mention a proper IDE – it was before Microsoft came around and fixed a few of the rough edges of their C++ IDE. There was no CLion. QtCreator was quite weak and buggy. Don’t get me started on people that thing that vim is a proper IDE – there were enough of these as well. So no, that day it was impossible for me to love C++. In a sense, it still is.

I will repeat that joke, though. What does the 11 from C++11 mean? The number of feet they glued to the octopus to make it a better. This is felt throughout the language, and today the first thing I suggest to people is to stop thinking that C++ is a superset of C. It is, but let’s forget that. That’s what Kate Gregory suggested a long time ago, and she made a kick-ass presentation at CPPCon about it1)Sidenote: my girlfriend, not a programmer, really liked her presentation, she thought she was kick-ass.

I’ll rehash a bit the ideas I had back then. I wasn’t that stupid, I just wasn’t offering the proper arguments. So let’s see:

C++ IDEs suck.

As of 2016 they still do. You can take each IDE and find incredible sucky points, but they all come from the same root cause – it’s not the complexity of the language, but from the fact that they try to offer too much or too little. The offer is quite big, I will make a simple list of things I don’t like “at a glance”

  1. Visual Studio: they made it a bit uglier, but they actually support C++17 (as much as they can). That’s amazing, but the IDE is still a pile of confusion when it comes to including an external library in your project. If I remember correctly, while they offer a standard C library it still matters if you compiled your library for multithreaded debug or for single threaded release. It’s hard to reference a library, it’s hard to deliver a library with your executable. You still have to deliver a runtime.
  2. CLion wants to be the big, smart guy in this area. I actually bought their IDE. I love it, it’s pretty fast, it’s neat, it’s responsive (except when it’s not). They only support cmake (and cmake is horrible, you can’t write proper modules without a lot of pseudo-coding in their funky language which I don’t care about and don’t want to learn). They don’t deliver a compiler that compiles stuff on the platform they deliver (they don’t have a MSys/Cygwin like system that actually works, I wish they would). They don’t support remote debugging.
  3. QtCreator is the IDE I really wanted to love. It’s focused, it is obvious that it’s inspired by the old Visual C++, the good one. It delivers its own tools, which is a plus. But you can’t create qmake projects if you have a cross compiler or you don’t have a Qt library in that toolchain, and qmake is the only sane way do projects (simple, without complex programming of features in strange languages. But limited and badly documented 🙁 ). QtCreator is, like CLion, an IDE I really really want to use, but it’s hard to when it suggests I should do manual steps in order to do what they could easily automate. I know, it’s open source and I can help improve it.
  4. Eclipse. Eclipse is huge and offers an amazing set of features, alongside lack of speed and yet another build system. If you go for an autotools project you simply forget that it has those features – it manages to hide all those features from you or forget that it has them. For example there’s no way to deploy and debug remotely if you use the autotools project. You have addins for everything, but it’s a moody system (for example it keeps forgetting my settings for the toolchain if I click on the wrong area, and it keeps forgetting that when I hit debug I really want to go on the remote platform because I use a cross compiler. Eclipse is not a C++ IDE, perhaps Java developers are more accustomed with tools that they can’t understand and they have to perform magic in order for them to work relatively appropriate.
  5. Netbeans. Faster than Eclipse, pretty much the same deal.
  6. KDevelop is getting worse and worse every year. In 2003 I was working on real, production projects with KDevelop, I wouldn’t entrust my code to KDevelop now.
  7. [Your favorite IDE here]. To put it plainly it sucks as an IDE (perhaps not as a glorified code editor). You can include here Code::Blocks, Vim, Emacs, SlickEdit, etc.

For each IDE there are a lot of points I could hit on. I chose the things that really make me hate them.

It’s a barely manageable language

I think that was one of those misunderstood points. My point was that there is no clear flow to work with the language. That can be a blessing, it allows a lot of freedom. That can be a curse. Let’s discuss the downsides.

  1. The split between source and headers, which makes project management quite slow. If you make all header libraries you’ll have a lot of copied code – the binaries will be larger. You’ll have to recompile that code every time you want to use it. And the split between the two is always troublesome – you can’t add a new field to your class without a few CTRL-TABs until you find where to write the proper definition.
  2. You still can’t write template code in .cpp files. You have to write code in the headers. If you mix that with some #ifdef & friends, it becomes a mess quite fast. Not to mention that you include content that is really implementation dependent.
  3. C++ still uses the C preprocessor. That is the first feature that should’ve gone from the language. If you think about it, the header should represent the features that your object offers and not a letter more. However, people ended up delivering these huge files that can be used everywhere even if they will be used in one place and one place alone.
  4. Namespaces are useless and make the code way too verbose. Instead of making your code cleaner and clearer, the programmers will end up doing a using namespace xxx. If you don’t believe me, look at how the code for using the duration_cast looks without some usings (auto only hides the dirt under the rug).
  5. Lack of ABI makes it impossible to deliver C++ components without a C interface. If you don’t, you’ll crash quite fast when you use the flag -fsuper-duper-new-feature because you should’ve used the flag -fsuper-duper-extra-cool-newer-feature.

5 are enough. There are others, but let’s move on.

It’s a barely portable language

Theoretically you write stuff in one place and you should be ready for… wait a minute. Did you really use <unistd.h>? And did you dare use the std::to_string call? You’re stupid, that doesn’t work under the C++14 compiler under Windows except for Microsoft’s. Why? Well, why not? We love to be arbitrary like that.

Portability is a hard thing in C++. You have to work for it, you have to make sure that you’re doing special stuff for it. C++ is amazing, don’t get me wrong, but in the past 15 years the only non-portable code I’ve seen was written in C++, or was caused by the interaction with a C++ native layer. C++ is mostly portable except when it’s not.

I think it’s easier to achieve true portability under C# or Java, because there’s an “all or nothing” feeling about them – either they have the whole core system ported, or they don’t work at all. That said, you still end up using C/C++ layers, and I love C++ for that, but remember, I offer a look at the bad part.

It’s a counterproductive language

I like to call myself stupid. It’s obvious that I am, that’s why I became a programmer – to make computers do the work for me, because I’m not to be trusted. That’s the case for my instant crush for C# – they have one simple model to refer resources – pointers, hidden by the lack of special notation – moron friendly, so it was a natural match.

I wanted to start a Breakout clone in C++. I had an array of widgets. Those widgets had textures. Those textures were copied over and over and over again, because containers can do that, so I had to go back to rethinking the storage class for the widgets.

I explained about the productivity hit I have when I have to search for a header file and add a few bits there, then go to the constructor (another file) to initialize it, then implement its usage in the header file (because templates) then go back in the other file to make sure another function makes proper use of it. If you put this in the context of IDEs unable to add a field to a class or rename a field of a class…

You can’t just take a DLL and use it as such. You need to have a “development package” which consists of pre-built binaries and huge header files that you need to compile with certain flags.

Should I go on? It’s kind of late for me, so I’ll just move on to the next chapter:

STL and Boost suck

They do suck and they suck big time. Please have a look at this wonderful code:

I can’t really write this from memory. And even if I could , I wouldn’t, it’s insanely long. I can write the code below without looking at the API, though:

Which one is more readable? I know that the C++ version can do some amazing tricks. I could write the C++ code from memory, but I refuse to keep this in mind. And that std::chrono is really killing me.

When you compare the amazing Linq extensions to the STL algorithms that are ugly to use and unreadable in the final code, you really wonder why should you even bother. Let’s compare.

C# equivalent (and seriously written from memory)

Notice the “unreadable code” from C#, even the portability issue (hint: \n does not always do what you think it does). And there’s no reason why the C# version would be any slower than the C++ code, if you don’t mind the JIT work.

I’m comparing C++ with C# because it’s easy for me to write C#. And it would not be very hard for the C++ standard library to look as readable. STL has bad names for everything, especially that erase/remove thing which doesn’t do what you think it does. Then push_back and emplace_back, which is the sort of distinction that shows you’re not focusing on the task to solve, but on how the function that you use works. You’re spending time thinking about a very specific detail that you should really not care about. You should use the fastest (which is emplace_back, I think).

Then you have the std::shared_ptr or std::unique_ptr, which you should see a lot more often than the poor *. The code becomes incredibly hard to read when it has a lot of text with tags in them, like X_ptr code does. It really looks ugly, and things like these add-up, they make STL horrible to work with. And now Boost. Boost is a huge thing. Once you get to use a bit of boost you get to use a lot of it, it’s inescapable. And the APIs are quite bad, in tone with the STL badness. I’m sick of underscores in APIs, (underscore is hard to type), but that’s not why I dislike Boost. I’m sick of stupid naming of things, but that’s not why I dislike Boost. I dislike Boost because it’s too big and I cannot really follow their complex mindset. I still have problems accessing their simplest APIs, the documentation is, as always, amazing except when it isn’t, and so on. And the reason for the added complexity (and their almost autoerotic obsession for templates)? Well, it’s mostly header-files, therefore what you don’t use will be thrown away. Ah, perfect, but I still have to compile it every single time.

I will not cherry-pick the bad examples from boost because I really don’t want to search through the garbage bin to show you stuff that are messed up and degraded. What’s clear, however, is that boost libraries are a guarantee that your resulting code is as template heavy and as unreadable as possible. If not, that’s fine, there is a new release right around the corner. And I’ll leave you the freedom to tell me that I’m ignorant and I don’t know boost. I don’t, and, most importantly, I shouldn’t. These things shouldn’t be memorized.

C++ sucks

It does. There is a fun subset, it’s fun to have immense power, but as a language it can suck a lot. STL is ultra-verbose, namespaces are useless, you shouldn’t use features that are there to be used, and so on. The language is too complicated, it respects too much of the C legacy, and C can be a messy language. It doesn’t offer you the possibility to transmit a minimal set of binaries with self-describing metadata, we need to build huge kits for development. C++ is the immature old man of the programming world.

I still love C++, despite what redditors think, but it’s still ugly from many points of view.

NOTES   [ + ]

1. Sidenote: my girlfriend, not a programmer, really liked her presentation, she thought she was kick-ass

Comments

Why C++ sucks (2016.02 edition) — 27 Comments

  1. Pingback: The day I gave up on C++ | dorinlazăr.ro

  2. you have many, if not all, valid points.
    it’s hard for me too giving up on c++.
    just out of curiosity, what programming language(s) do you like better and prefer for professional use?

    • I like C# a lot, and the Microsoft guys are opening up a lot lately. That said, I still love C++ and I am in the process of recommending it for a real-life project.

  3. I’ll be going through the Article in more detail later. I may even write a post about it. For now: I don’t quite understand the problem with the C++ code snippet you provided. I think it’s quite readable.

    Also, why would you recommend C++ if you find it so horrible? Could it be that you like to exaggerate a bit in your articles in order to make a point?

    • Hi Joseph,
      I chose the code randomly. Generally, the density of the code becomes problematic, the code becomes unreadable very fast. You can’t really compare x.Any with std::all_of(foo.begin(), foo.end(), [](int i){return i%2;})

      Why I recommend C++? Because it’s the sensible choice for the project I’ll be working on. It doesn’t mean that these points are not issues I will have to work around, it just says that there are huge points to improve. If the Modules standard is adopted, half of the issues are gone, I think.

    • You really think the C++ example is easily readable? There’s way too much gibberish. There’s a story about the making of the first commercial television sets. The company owner asked the engineer if every part was essential; he was assured it was. The owner then reached in, yanked out a part and then turned the set on. It still worked. He did this again and it still worked. He kept going until the 8th part, when it didn’t turn on any more. He replaced the part, then said to the engineer, “THAT’S how I want you to build television sets.”

      In python, the example would just be:

      arr = [3, 5, 7, 11, 13, 17, 19, 23]
      if all(num % 2 != 0 for num in arr):
      print(“All the elements are odd numbers.”)

      No begins and ends, no <<, no semicolons, no ::, no empty brackets, no returns… just like that first television set, only what you absolutely need to represent the solution. In fact, it’s a lot more readable than the C# program too – no namespaces, classes, usings, static publics, no cascading closed brackets. It’s only just cleaner than the elegant Rust example that was already posted.

    • @Joseph Mitzen
      ‘He kept going until the 8th part, when it didn’t turn on any more. He replaced the part, then said to the engineer, “THAT’S how I want you to build television sets.”’

      In the end the engineer made a TV that wouldn’t display any images, couldn’t change channels, adjust brightness or contrast, overheated and eventually exploded after 10 minutes of use. But it would turn on. And that’s how no one has ever heard of that company again.

  4. I personally think that author is one of those wanna-be pseudo programmers I have met during my studies at college, who ended up doing yet another todo-list/calendar/insert any other generic useless app as their job. Author did not mention std::endl, used ‘using’ in C# examples while no using namespace was used in C++ one. The fact that you have written C# code from memory is purely because you are more used to that language. I would write C++ one from memory but not the C# one. I do not think that C++ sucks, I suck.

    • That’s a load of hogwash. I have been coding c++ everyday for more than ten years and c# every day for maybe five, and I totally agree with the author that there are things in c++ that just don’t stick in my memory. Like iterating over an STL list for example. I don’t use STL all that much but when I do I find I almost always have to look up examples of how to do the most trivial things. In c# on the other hand, while it is hard to forget “foreach Foo foo in foos” and usually I just type “foos” press the hotkey in resharper “iterate with foreach” and have it fill in the rest, which makes for a much nicer experience than struggling with some fucking iterator object.

  5. “I like to call myself stupid. It’s obvious that I am, that’s why I became a programmer – to make computers do the work for me, because I’m not to be trusted.”
    Awesome! Can I use it as a motto for my projects?

  6. This wasn’t an option back when you wrote your original article, but have you taken a look at Rust? It’s a C++-alternative from Mozilla designed for writing browser engines, so it has the same focus on performance (no garbage collector, based on LLVM like Clang) but with an emphasis on memory-safety and the benefit of being designed as a whole rather than piecemeal. I can write your Linq example in Rust from memory without difficulty:

    • Two reasons why the .iter() is needed:

      Rust has a whole lot of those Linq-style methods like .any() (Rust calls them “iterator adaptors”, see the list here: http://doc.rust-lang.org/std/iter/trait.Iterator.html ), and it’s easier to implement all those exactly once in the standard library, and then containers can simply implement .iter() to return an iterator and thereby automatically be able to use all those adaptors without any extra effort.
      The price of being memory-safe without any garbage collection is that Rust has to care a lot about the ownership of data (same as in C++, except in Rust this is enforced by the compiler), and there are multiple ways of creating the iterator: the .iter() method takes elements to the underlying collection by-reference, while .into_iter() creates an iterator that takes elements to the underlying collection by-value.

  7. STL sucks, but Qt don’t.

    QElapsedTimer timer;
    timer.start();
    f();
    qDebug() << timer.elapsed();

    Or:
    QTime t1 = QTime::currentTime();
    f();
    QTime t2 = QTime::currentTime();
    qDebug() << t1.msecsTo(t2);

  8. Good points on the topic, but really man, programming is not something that is easy. There are no perfect solutions. Yeah, C++ sucks a lot in some areas, and it is very difficult, but it can be a very powerful tool and something that you can enjoy programming once you get into it.

    You kinda diss all the IDEs out there. Why not write a good one yourself ? 🙂

    Please, learn to use these environments properly before you diss a perfectly fine programming environment like VIM just because you don’t like it. You come out as somebody very arrogant this way. VIM and other programming editors have been here way longer than any IDE Microsoft has put out, and there is a reason for that.

    Anyway, always enjoy reading about C++ and people ranting, but this writing reveals more about yourself than the language or environments.

    Ps. Writing a C++11 & Lua 3D -engine at the moment, it’s a very nice combination, went through the route of trying to do it with C++11 only but yeah that was frustrating and slow, combine the speed and flexibility of C++11 with a scripting language like Lua and you have a very nice combination.

  9. (hint: \n does not always do what you think it does)

    Wrong, std::cout is in text mode, "\n" is always translated to local newline sequence.

    I also see no reason why are you obfuscating your C# example with !x.Any(x => x % 2 == 0), instead of doing x.All(x => x % 2 != 0) which actually is readable.

  10. So you don’t agree, but can’t manage to directly refute a single point other than being condescending . I think that says everything anyone needs to know about you, none of it favorable.

  11. You can avoid ugly 3-level namespaces code of STL or Boost with the “using’ keyword:
    using CK = std::chrono::high_resolution_clock;//and so on
    auto time = CK::now();
    As for the build system: CMake or Scons, takes some time to get familiar with the scripting, but still finding or dependencies files by filter is(imho) better than adding separate files or libraries by clicking dozens of buttons in one of MS IDE’s menu.

  12. Many comments on std::all_of readability, but the important point is still missing: std::all_of is flexible; you can choose to start the algorithm at any element of the array whereas you can’t with C#’s Any.
    auto it = std::find(std::begin(arr), std::end(arr), x);auto ok = std::all_of(++it, std::end(arr), [x](auto&& i) {return i == x;});

    • Indeed you can’t because you don’t need that. Instead you usually need it for the whole collection. However, you have more refined ways to select things like this from a collection (if you need to restrain the collection to a subset). You can’t (in C++ with standard algorithms) skip ever other item – you can perform a Select on it first in C# and have a customized range. And you can easily restrain the range with things like: collection.Skip(5).Take(10).Any (i=>i==x).

      Eric Niebler’s efforts in this area are notable – but until Eric will not finish his work we are at a point where we are verbose for nothing.

Comentariul tău