This popped up on youtube today, it's a Livestream with 24k live viewers, claiming to be a Linux Foundation Livestream that gives free bitcoin to people who send them some first.
This pops up again from time to time, I think what people should take away from this is that garbage collection is not just what you see in Java and other high level languages.
There are a lot of strategies to apply garbage collection and they are often used in low level systems too like per-frame temporary arenas in games or in short lived programs that just allocate and never free.
Once you set a limit like this, though, it's brittle, and your code becomes less maintainable or flexible in the face of change. That is why a general purpose strategy is good to use.
I believe the person who started this is just a bad actor.
Surely he must have known that this will only lead to more outrage and hatred.
Now we need to have the whole "war on xmas" and "political correctness gone crazy" debates, just because there is one idiot out there that people decided to listen to instead of ignore.
Thanks for the comment, I might steal your "subset of C99 which compiles both in C and C++ mode on GCC, clang and MSVC" quote and put it in the article if that's ok ;)
Hi, the reason for using C99 is that it is fully compatible with other languages.
If you write a library in Rust you might be tempted to use Rust only feature which will then make it hard to wrap the library for other languages. And if you don't use those features from Rust in your library people will comment that your library isn't Rust enough. Same thing applies to C++.
To that extent my advice is to write C in C rather than C in Rust or C++.
Also if people don't have a Rust toolchain setup, compiling the library and using it from source would be hard. In some cases integrating Rust in their toolchain could be hard.
Regarding metal and vulkan I will edit the article to mention Vulkan there too alongside metal. Thanks for your feedback.
I suppose wrapping it for other languages can be harder, but should be doable I think. The benefit of Rust though is using a much better language with rich standard library.
As for toolchain, Rust can be set up basically anywhere llvm can, which is quite a lot. There are rare cases where llvm wasn't ported yet to, but I don't think they are enough to make C a compelling option in general, and I don't think any of them are gaming related.
If you are in such case - then sure, but otherwise, I'd still prefer Rust.
I think the Rust standard library is actually a liability in this case, not an advantage. The rust stdlib will essentially be an extra dependency and also the rust standard library doesn't have allocators, so unless you are very careful you might violate the principle of not doing allocations for the user. Also, even if it did have allocators, passing allocators from to Rust via a C interface would probably be awkward.
So if you do choose to make the implementation in another language, there are extra considerations that you have to take into account.
Hi, I mention in the article that "It is easier in general for a C++ user to use a C library than it is for a C user to use a C++ library." which is where the advice comes from.
I agree. But "wants" is a term indicating personal preference. I understand that C is best suited for maximum portability and performance. But as a C++ developer I prefer libraries that come with C++ interfaces (and you do mention that it is good to provide a C++ wrapper as well).
Thanks a lot for your feedback. I decided to remove that since I think you are right about indicating personal preference.
I do not want this article to be a list of preferences but rather an analysis of the considerations that popular C libraries make (eg: stb, sokol, etc) and that new authors should also reason about.
Because the binary interfaces generated by C libraries are simple and therefore universally supported. It's just normal symbols and calling conventions. Conforming to this ABI benefits users of every other language, not just C++.
C++ ABIs are rather complex and much harder to interface with. The existence of concepts like virtual functions and exceptions significantly complicates the implementation of foreign language interfaces.
If you are interested in learning more about writing complex software in C consider checking out HandmadeHero.
Sadly there need to be more good resources on learning how to write good C and low level software.
I am hoping my article can be a starting point for people who wish to learn about library design for example.
Hi, thanks for your feedback.
I am the original author.
Regarding prefixes, I advice that you start by writing the library in C and then wrap it in C++ for a variety of reasons that you might want to consider. In C++ you should indeed always use namespace.
Header guards have the advantage over pragma once that they are standard and you can also use them to check if a library is included. I might remove that since maybe it's not that important and people might different views.
Regarding constants, I was referring to things such as numeric constants for which you would constexpr in C++. Maybe I can be more explicit there. Thanks for the feedback.
I advise you start by writing the library in C++ and then wrap it in C if you need C ABI of the library.
It’s very hard to write correct C code which does IO and supports multithreading. Take a look at Microsoft’s implementation of fprintf, copy-pasted from Windows 10 SDK: https://gist.github.com/Const-me/f1bb320969adde6c79694265ea6... They use RAII to set & revert the locale, and to lock RAM buffer to avoid corruption by another threads. They use C++ lambda for exception handling. They even use C++ template to avoid code duplication between printf and wprintf.
But these C++ shenanigans are not exposed to user, user calls their `printf` (possibly in a code built by C compiler) and it just works.
> It’s very hard to write correct C code which does IO and supports multithreading
This is just a random unsubstantiated statement. There's nothing particularly "hard" about writing IO libraries that is language-specific. Multithreaded or not.
When you do IO and multithreading, functions often need to acquire and release stuff: mutexes or other locks, resources, locales. Even more so in videogames, e.g. OpenGL code often calls glMapBuffer / glUnmapBuffer many thousand times each frame.
The hard part is making sure you release stuff every time you acquire stuff, exactly once. C++ RAII makes it almost trivially simple, but standard C has nothing comparable. When you only targeting gcc and clang can use __attribute__(cleanup) in C, it helps but still it’s more limited and more error prone compared to destructors.
It’s easy enough to correctly use a small API in a small program. It doesn’t matter at all for short-living apps which clean up their resources by exiting the process.
There’re also other programs in wide use, which need to reliably work for hours, sometimes weeks. Some of them have huge amount of code they built from, written by many people over many years. Combine that with large enough APIs (some peripheral devices have hundreds of writeable registers of state; or D3D11 exposes huge amount of very complicated state, only limited by VRAM amount which is measured in gigabytes) and it’s very easy to make bugs in such programs.
Leaks of memory, handles, sockets, and many other resource types e.g. GPU ones. Deadlocks caused by locked mutexes, or threads which exit but forgot to release something they needed to release. Unwanted changes to global or thread state, both internal to the process and external (locales, formatting options, console colors, process and thread priorities, current directory, environment variables, CPU registers like FPU flags and interrupt masks, GPU render states) caused by some code changing stuff but not reverting the changes back. Unwanted state changes of custom peripheral devices, due to the same reason.
C++ RAII is not a silver bullet, but it does help a lot for all these things.
It's easy enough to implement correct API usage semantics in a program of any size.
If you need to rely on RAII in order not to screw things up, then it's an issue with the coding style or the application design. That's what needs fixing. Not the language choice. You got it backwards.
It’s a hard problem, and language + runtime support helps. That’s why C++ has RAII, C# has IDisposable / using, Java has try-with, python has enter / exit / with, golang has defer, and so on. The only reason C has nothing comparable, it’s almost 50 years old now.
The problem is only tangentially related to API semantics. The problem is mutating state. The state is not necessarily managed by an API, for instance CPU registers aren’t, you modify them directly. Same with other global state like I/O formatting options and locales, these things are just global variables.
Hi, I am the author of the article.
Regarding RAII, what I mention in the article is that it is ok to provide RAII wrappers as long as you also provide C++ wrappers for the non-RAII plain structs and functions from C.
I think this is the best way to satisfy everyone.
When it comes to exceptions and rtti the sad reality is that about 50% of the C++ community doesn't use (for one reason or another), so if you do use them in a library it can have an impact.
I also gave an updated version of the talk at embo++ with some small updates and fixes to some code examples, not sure if that will be on youtube but you can see the slides here: https://docs.google.com/presentation/d/1tHdUBWSf8oVbX8Oe4V15...