Hacker News new | ask | show | jobs
by qalmakka 1968 days ago
I think that 3/4 of their issues would probably be solved by a well thought use of modern C++. I've seen too many C projects (including some of mine) starting by swearing out C++ for one reason or another and then ending out reimplementing half of it using macros or poorly written hashmap implementations taken from somewhere.

Glib2 is one excellent example of how people have been shunning C++ due to its complexity, while on the other hand implementing overly complex libraries to mitigate the fact it's too barebones, which is oxymoronic to me. Either you say C is better because its simplicity and you keep stuff simple, or you are just being a zealot for the sake of it.

Basically everything I can put my hands on supports C++, I've been running massive applications on embedded microcontrollers and it works as fine as C. If you don't like some features, just write C-style C++, use the C ABI and #include <> all the containers you need.

6 comments

Absolutely. It makes perfect sense, and in an ideal world this would be the direction which would benefit many, if not most, projects using C and/or GLib2. Unfortunately, there are far too many people who are wedded to the philosophy that C is perfect for every task, and C++ is the devil. Despite the fact that GLib/GObject are more complex than C++, more error-prone than C++, slower than C++ and make static code analysis impossible (due to all of the unsafe typecasting).

A few years ago now, I ported a C GLib/GObject-based application to C++. In removing all of the unnecessary typecasts I found a couple of minor (but real) bugs which were previously hidden from the compiler. Simple use of real classes, along with basic containers like vector and map, was the vast majority of the C++ usage in the whole application. It benefitted greatly in becoming smaller, simpler, easier to read, easier to maintain, and having the compiler able to typecheck everything.

Like yourself, I've also used C++ on MCUs. Some vendors even provide an "Embedded C++" C++ subset you can use, which is "safe" for safety-critical real-time code. Works fine. A lot of C embedded projects would benefit from the extra safety it provides. So long as you don't go overboard with the features; stick to a simple and easy to understand subset.

I gateway drug to C++, was Turbo C++ 1.0 for MS-DOS, released in 1990 as per Wikipedia. I got my copy in 1992.

Basically C++ARM as per language standard, on a 386SX running at 20 MHz, 2 MB but 640 KB was more than enough, right? :)

Our high school teacher giving us C classes with Turbo C 2.0 also had it around, so as it were back in those days, I eventually got a copy.

My gateway drug to programming until then were Turbo Pascal 6.0 and TASM, and C++ was in the same ballpark of features and culture for safer systems programming.

Never had any issues using it in such kind of PCs, including with my own bounds checked string and array classes, hardware that most modern MCUs can easily outperform.

Absolutely. Modern MCUs are phenomenal. More powerful than mid '90s top-end PCs. Add some external SDRAM and storage, and they have more and faster memory and storage as well. C++ is perfectly good. Better than all the nasty C macros in the vendor HALs, if you replace that nastiness with some type-safe enums and inline functions. There's plenty of capacity for running Python or Lua as embedded scripting languages even on smaller variants, both of which wrap C++ nicely. I'm fairly new to the embedded world, but so far it's been mostly a pleasure to write code for a variety of TI, ST and Nordic MCUs; some with C, some with C++.

I do see why people like C for embedded use; when it comes to hardware interaction you have complete visibility into all of the interactions with special registers. Looking through the disassembly when debugging is nice and straightforward. But C++ does this and more, so long as you don't go overboard with unnecessary complexity. It's fine with a bit of self-discipline, and all that extra bounds checking and such is of value.

In case you never seen this, enjoy Jason Turner's “Rich Code for Tiny Computers: A Simple Commodore 64 Game in C++17” talk. :)

https://www.youtube.com/watch?v=zBkNBP00wJE

Agreed in general on using C++ over C, or C-style C++ in constrained environments. One thing that is nice about using C though is that it is quite easy (compared to C++) to expose to other languages. Glib, and most libraries built on it like GTK, GStreamer, etc can be used in languages such as Python, JavaScript et.c.. And a lot of development of applications and tools has been moving to such languages over say C++. So C is still useful for low-level libraries, due to being the lowest common denominator. Though arguably one could today write the library core in a better language like Rust maybe, and expose a C API/ABI from that. Rsvg is growing into an example of that.
C++ seems difficult to embed because there is no standard way to expose features that don't map well to the C calling convention. Just use `extern "C"` if you want a C API. For everything else you'd have to commit to an application binary interface first, such as GObject, COM or the CLR. You need these to define calling conventions and semantics (such as initialization, exceptions, memory and resource management) well enough that other languages can bind to them.
I look forward to it eventually to grow into OS vendors SDKs, at very least those that provide llvm based toolchains.

Until then C++ will do.

Do you mean glib? It is in every server and desktop Linux distro, including those with commercial support from RedHat, Canonical and SUSE. For embedded Linux devices glib is included in Ubuntu Core from Canonical, as well as Wind River Linux from Intel. The GStreamer SDK includes glib and is supported by Fluendo and Collabora on Android, Windows and Mac.
Not at all, I mean Rust being available alongside C and C++ on OS SDKs, regardling tooling, IDE and libraries.

A checkbox on the installer, with first party support.

There is one significant thing that C has and C++ has not; a stable ABI. This is particularly important if you want to create a library that can be shared and used by everyone. You cannot do that with C++ without a lot of caveats. Google, for instance, forbid creating libraries in C++ for good reasons. Creating a C++ library with a C ABI sounds stupid. I.e. if the library’s functions and types can be presented as simple C, you have already folded down to C and C++ is just an implementation detail and you will probably also have to static link libstdc++. That’s no longer a small, simple library anymore. The stable ABI makes C also famously easy to include and inter opt with other languages and frameworks. Swift for example can easily utilize C libraries and code but cannot inter opt with C++ (yet, apparently it’s wip)
C++ was already everywhere on desktop computing back in the 90's, with Apple, IBM, Microsoft, BeOS adopting it on their frameworks, and even on the mobile with Symbian.

Then FOSS happened with its manifesto to use C for portability, war on KDE due to licensing gave raise to Gtk and related eco-system, and here we are.

Thankfully I learned C++ on MS-DOS and became enlighted, even with its 640 KB limit it was already so much better than the primitive C, in regards to type safety, generic code and yes RAII was already a thing.

The main practical benefit of C is the simplicity and stability of its ABI.

There are currently 8 different language bindings listed on LibVirt's website. It's not clear to me that this situation would improve by switching to a language as notoriously difficult to interop with as C++.

https://libvirt.org/bindings.html

The point is, C++ supports the C ABI. You can write your entire application in C++ and expose only a C-style API with the stable ABI you wish. I've done it a million times and it's absolutely fine.
For long applications you get into he realm of tool chain bugs with C++. C compilers are more reliable.

If you write C-style C++, which parts of libstdc++ can you safely use without exceptions?

> which parts of libstdc++ can you safely use without exceptions?

Almost all of it, as long as you're happy to abort on memory allocation failure - which, according to the article, libvirt is now willing to do.

In fact for me, that's one of the main questions to ask when deciding between C and C++ for a project. Is it OK to abort on allocation failure? If so, use C++ (without using exceptions). If not, use C.

Google writes a lot of C++ code, disables exceptions entirely, and it does not shy away from STL at all.
Then they don't care about applications being terminated in case of std::bad_alloc and similar.

The crucial applications they use are written by others (like the Linux kernel).

Also, having seen the output of several Googlers, I think their code quality is overrated.

> Then they don't care about applications being terminated in case of std::bad_alloc and similar.

No, they don't: https://youtu.be/NOCElcMcFik?t=2304

   auto ptr = new (std::nothrow) ......
   if (ptr != nullptr) {
       //........
   }

Regarding STL, allocators with similar behavior can be provided.