Live data from Hacker News

How to write better game libraries

handmade.network

81–90 of 129 posts

Re: How to write better game libraries

#81
The problem for game libraries in general is that game dev lives in c++ world and c++ is awful for libraries. Most c++ devs I know would rather start writing a program by defining string than by learning to handle proper library management tooling. I'm not an expert so I'm not sure if it's just a culture thing or if there are inherent features in the language that make library usage hard, but yeah. That's that.

Re: How to write better game libraries

#82

Earlier quoted context omitted.

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 corrupti…

> 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.

Re: How to write better game libraries

#83
post #80
post #70

Earlier quoted context omitted.

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.

Re: How to write better game libraries

#84
post #12

Earlier quoted context omitted.

FWIW I’ve never been at a job that allows exceptions...but smart pointers and RAII are great.

On the other side of the coin, I don't think I've ever had a job in which anyone would have ever considered banning exceptions (although I have worked at some where people did know that some other companies did ban them). The world of programming is a very broad church indeed.

Examples of companies or projects that ban exceptions

Google, and therefore Chromium

https://google.github.io/styleguide/cppguide.html

Mozilla, and therefore Firefox

https://firefox-source-docs.mozilla.org/tools/lint/coding-st...

I'm pretty sure WebKit also doesn't use exceptions. It's not listed in their style guide but searching the repo I don't find any instances and the repo history shows turning them off.

Re: How to write better game libraries

#85
post #23

> Write the library in Standard C99 Why not write it in Rust, and provide C99 bindings? Using stock C for the actual library doesn't sound like a good idea to me, when today there are better alternatives. And for sure avoid using Metal lock-in directly. Use Vulkan, which Apple should have supported from the beginning. For lock-in targets, there are translation options from Vulkan.

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.

Re: How to write better game libraries

#86
post #53

Earlier quoted context omitted.

> I know only 1 mainstream platform where C++ adds significant friction compared to C, that’s iOS, because their objective C is a superset of C. Apple’s compiler supports overlaying Objective-C features on top of C++ instead of C; it’s called Objective-C++.

I once forked a C library, porting some parts to C++ in the process: https://github.com/Const-me/nanovg/ I’ve retained original C API, only used C++ in the implementation. Then I’ve got an e-mail from a developer who asked a few things how to back port my changes to C. I answered their questions, but I was curious why. They replied it’s because Objective C and iOS. Personally, I haven’t been developing for iOS for se…

That developer must be misinformed. I have been developing a native component that needs to interface with C++ APIs from the app and Objective C APIs from iOS. The only thing you need to remember is to not mix exceptions from C++ and Objective C. The object models are also incompatible, but the compiler prevents you from mixing them.

Re: How to write better game libraries

#87

Earlier quoted context omitted.

> 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.…

> The * hard part * is making sure you release stuff every time, exactly once.

Oy vey... you can't be serious. That's rudimentary basics of using any API.

Re: How to write better game libraries

#88
post #85
post #23

> Write the library in Standard C99 Why not write it in Rust, and provide C99 bindings? Using stock C for the actual library doesn't sound like a good idea to me, when today there are better alternatives. And for sure avoid using Metal lock-in directly. Use Vulkan, which Apple should have supported from the beginning. For lock-in targets, there are translation options from Vulkan.

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 r…

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.

Re: How to write better game libraries

#89

As a warning: While C99 is a really nice language - especially over C89 - please note that the Visual Studio C compiler still does not support the full C99 specification, and it is not possible at all to compile C99 as C++ code (which sometimes is useful). I usually recommend to write library-level code in the "subset of C99 which compiles both in C and C++ mode on GCC, clang and MSVC". This is basically a version of…

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 ;)

Re: How to write better game libraries

#90
post #87

Earlier quoted context omitted.

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.…

> The * hard part * is making sure you release stuff every time, exactly once. Oy vey... you can't be serious. That's rudimentary basics of using any API.

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.

Post reply on HN