News for hackers. Stuff that matters.
Re:How to write better game libraries by Const-me on Sunday December 08, 2019 @04:23AM (#21735054)
Some of these recommendations are awesome, others aren’t good, IMO.

> Always prefix your names to avoid name collisions

Solved by C++ namespaces.

> Use header guards instead of #pragma once.

#pragma once is supported by all mayor compilers, header guards can introduce bugs, also #pragma once builds measurably faster: https://github.com/electronicarts/EASTL/blob/3.15.00/include...

> Expose constants to the user using constexpr variables.

Modern C++ has strongly-typed scoped enums for such constants.

Re:How to write better game libraries by LucaSas on Sunday December 08, 2019 @09:23AM (#21735998)
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.

Re:How to write better game libraries by Const-me on Sunday December 08, 2019 @10:12AM (#21736244)
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.

Re:How to write better game libraries by huhtenberg on Sunday December 08, 2019 @10:32AM (#21736357)
> 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.

Re:How to write better game libraries by Const-me on Sunday December 08, 2019 @10:57AM (#21736499)
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 by abcd_f on Sunday December 08, 2019 @12:25PM (#21736954)
> 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 by Const-me on Sunday December 08, 2019 @01:06PM (#21737165)
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.

Re:How to write better game libraries by abcd_f on Sunday December 08, 2019 @02:18PM (#21737625)
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.

Re:How to write better game libraries by Const-me on Sunday December 08, 2019 @03:24PM (#21738052)
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.

Re:How to write better game libraries by kd5bjo on Sunday December 08, 2019 @04:27AM (#21735065)
C++ features don’t help when you’re programming in straight C, as the article advises.
Re:How to write better game libraries by pjmlp on Sunday December 08, 2019 @04:41AM (#21735103)
Other than UNIX like kernels and tiny PIC micro-controllers no one else should still be programming in straight C in 21st century.
Re:How to write better game libraries by huhtenberg on Sunday December 08, 2019 @10:41AM (#21736408)
Reading through your comments the only take-away appears to be that you just really don't like C for whatever reason.

C is a perfectly fine language for tasks of all kinds. The fact that it expects programmers to take greater care when using it is not a reason enough to dismiss it as a general-purpose language. Not everyone needs (or wants) to ride a tricycle wearing knee pads and a helmet to get from A to B.

Re:How to write better game libraries by pjmlp on Sunday December 08, 2019 @04:52PM (#21738632)
Ah the old straight jacket argument against computer security, never gets old.

The reason is very simple, the billions of wasted money fixing security exploits caused by industry's adoption of C.

Morris worm is more than 30 years old, and the old ways can still be used to attack modern systems that people insist in writing using C.

https://msrc-blog.microsoft.com/2019/06/14/prevent-the-impac...

https://support.apple.com/en-us/HT210348

https://msrc-blog.microsoft.com/2019/07/16/a-proactive-appro...

https://kernsec.org/wiki/index.php/Kernel_Self_Protection_Pr...

https://security.googleblog.com/2019/08/adopting-arm-memory-...

Re:How to write better game libraries by starsinspace on Sunday December 08, 2019 @08:38AM (#21735826)
I agree that "straight C" is not the best choice anymore... but C++ isn't great either. It inherits most of C's weaknesses and for libraries, it makes it very difficult to use the code from languages other than C++. By making a library in C++ you are basically limiting it to being used only in C++ projects. (Yes, wrapper generators for C++-to-whatever exist, but my experience with using e.g. Qt from other languages has always been pretty terrible).

Even in 2019, the C ABI is the one universally agreed-upon cross-language ABI for languages compiled to native code.

Re:How to write better game libraries by pjmlp on Sunday December 08, 2019 @09:54AM (#21736126)
In what concerns security, both should be nuked.

However given that at least C++ does support ways to tame C, after all the whole purpose was for Bjarne never to repeat his Simula into BCPL rewrite experience ever again, it is up for security conscious to decide what legacy they want to leave, when the option is between both those languages.

On the other hand maybe C should be used to write Skynet, so that we stand a chance.

Re:How to write better game libraries by kd5bjo on Sunday December 08, 2019 @04:53AM (#21735137)
That may be so, but the central thesis of the article is that C is the still the appropriate language in which to write libraries for interoperation. If you believe otherwise, I suspect that a rebuttal of the author’s arguments in favor of C would be well-received as a top-level comment here— there seem to be a lot of people that agree with you, but nobody has yet stated why they hold that opinion.
Re:How to write better game libraries by pjmlp on Sunday December 08, 2019 @07:02AM (#21735487)
Sure, first of all there is no such thing as C ABI, only OS ABI.

C ABI happens to be the mixed up with OS ABI, on OS written in C like UNIX clones, on mainframes, and other competing OSes that isn't the case, because they use other systems languages on their stack, or even some kind of bytecode based interoperability format.

However since the context here is game libraries, C ABI == OS ABI pretty much applies everywhere (except WebAssembly or Android JNI) and lets leave at there.

Since C++98, writing a library in C++, even if exposing it as extern "C", provides the following benefits for the quality of code implementation:

- less implicit conversions

- use of reference types instead of pointers for memory accesses we can be sure are never allowed to be null

- use of namespaces instead of Assembly style programming of having to come up with prefixes for code organization

- bounds checking for strings, vectors and other related data structures provided one uses the library types. They can even be left turned on for release mode, if the profiler shows there is no visible impact on hot paths

- use of RAII to manage library internal state and reduce leak occurrences

- ISO C++ working group is actually striving for reducing the amount of UB from its 200+ use cases, unlike ISO C group

- strong typed enums introduced in C++11 don't have implicit conversions and must map to their underlying types

- type safe compile time code execution, specially helpful in games, used for stuff like generating trigonometry tables

- templates as replacement for pre-processor magic that eventually goes subtly wrong when the #include order gets misplaced or too few parenthesis are used

If this still sounds absurd, well all major C compilers are now implemented in C++, Microsoft rewrote their C standard library in C++ with extern "C" entry points, Android NDK is actually implemented in a mix of C++ and Java (via JNI) also using extern "C" calls.

Re:How to write better game libraries by Const-me on Sunday December 08, 2019 @05:03AM (#21735164)
> but nobody has yet stated why they hold hat opinion.

I did, in my first comment.

C++ namespaces lead to much more readable code, compared to these prefixed names.

C++/11 scoped enums eliminate a class of bugs: when you have many different constants on the API surface, multiple functions accepting them, and erroneously use the constant of a wrong function. Example:

    enum Lod { Low, High };
    enum SomethingElse { Other };
    void setLoD( enum Lod v );
    void bug()
    {
        setLoD( Other );
    }
Re:How to write better game libraries by kd5bjo on Sunday December 08, 2019 @05:17AM (#21735201)
Especially with this expanded commentary, you do show some advantages of C++ over C, but you have only addressed the advice for how to proceed once you’ve chosen C and not the author’s reasons for preferring C to C++ (or any other language):

— Every language out there has a way to call into C

— If your code is slower than C, someone will rewrite it in C.

— If your library is written in C it means it can be used on any OS, console or mobile device and even on the web.

— Not everyone wants to use C++ (some prefer C).

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

— C++ is not as easy to write wrappers for in other languages.

— Unless you limit which C++ features you use (to the point where you are pretty much left with C) a lot of people won’t be able to use your library.

PS. If your original comment had been phrased the way you put it here I might have made the same comment, but I would not have downvoted it. Here, you’re at least providing some supporting evidence for your assertions which makes it a much more valuable contribution to the conversation.

Re:How to write better game libraries by Const-me on Sunday December 08, 2019 @05:44AM (#21735277)
> If your code is slower than C, someone will rewrite it in C.

When used correctly, C++ is not slower than C. Sometimes faster, a classic example is C qsort versus std::sort.

> If your library is written in C it means it can be used on any OS, console or mobile device and even on the web.

C++ is good in that regard. 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. The rest of them (Windows, Linux including embedded, game consoles, android) support C++ just fine.

> Not everyone wants to use C++ (some prefer C).

Most people are OK with C++, especially in the context of game development.

> to the point where you are pretty much left with C

No, not with C. Namespaces and scoped enums are awesome.

Another thing, inside the implementation of the library, you can use whatever C++ language features you please, even the features that would be inappropriate when exposed at the API surface of the library. For example, MS implemented parts of their C runtime library with C++ classes, RAII, lambdas and templates, eliminating duplicated code for char/wchar_t routines. Obviously, you don’t need C++ to consume that library, just C is enough, but it’s implemented in modern C++. On my system, that source is in "C:\Program Files (x86)\Windows Kits\10\Source\10.0.18362.0\ucrt\stdio\output.cpp".

Re:How to write better game libraries by comex on Sunday December 08, 2019 @07:36AM (#21735587)
> 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++.

Re:How to write better game libraries by Const-me on Sunday December 08, 2019 @08:01AM (#21735677)
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 several years, but I don’t think people would do such things for lulz.

Re:How to write better game libraries by oriolid on Sunday December 08, 2019 @12:00PM (#21736824)
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 by comex on Sunday December 08, 2019 @11:21PM (#21740375)
Also, if C++ is only used in the library implementation... you wouldn't even need Objective-C++ unless you needed to add Objective-C API calls to the library's own source files. Otherwise, you could just compile the library's source files as regular C++, and link them together with your Objective-C code. This works exactly the same way as combining C and C++, and Xcode (the IDE) has no issue with it. So it seems very likely that the developer was misinformed.
Re:How to write better game libraries by pjmlp on Sunday December 08, 2019 @08:57AM (#21735880)
Except that only old timers, have the Objective-C++ documentation available, because Apple has removed it from their web site.
Re:How to write better game libraries by orbifold on Sunday December 08, 2019 @09:22AM (#21735990)
It actually extremely easy to write C++ wrappers for other languages. Examples I‘m familiar with are pybind11 (similar to boost python) and the node C++ API. That other languages don’t have similarly convenient libraries is entirely their own fault.
Re:How to write better game libraries by jstimpfle on Sunday December 08, 2019 @04:49AM (#21735125)
If people choose to and it gives them joy, and they are productive and even learn valuable things, why not let them be?
Re:How to write better game libraries by pjmlp on Sunday December 08, 2019 @06:29AM (#21735399)
Because if someone else happens to use that library, it might blow up on their face, e.g. WhatsApp dependency on android-gif-drawable.

https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-1193...

Re:How to write better game libraries by jstimpfle on Sunday December 08, 2019 @07:05AM (#21735494)
Are you looking for a safe way to use your computer? Turn it off.

Other than that, I'm not surprised the file in question is C. Even ignoring the fact that it was you to get the link. And even ignoring that it's about a security problem...

Other than that, from a user perspective, software written in C is among the most reliable software I'm using. I'm looking at Linux, vim, xterm and so much of the infrastructure that I don't even know by name.

Some people value "security" more than they value the beauty of a nice, a maintainable, or a practical program. That's ok as far as I'm concerned...

Re:How to write better game libraries by pjmlp on Sunday December 08, 2019 @08:58AM (#21735896)
The guys attending the Linux Kernel Security Summit seem to think otherwise, plenty of stuff there to entertain yourself.
Re:How to write better game libraries by jstimpfle on Sunday December 08, 2019 @01:23PM (#21737267)
Sure there is. But never be blinded, Linux is very performant and rock solid from an end user's viewpoint. Sometimes it helps putting things into perspective.
Re:How to write better game libraries by pjmlp on Sunday December 08, 2019 @05:08PM (#21738719)
Re:How to write better game libraries by jstimpfle on Monday December 09, 2019 @09:12AM (#21742753)
If you like random links, here is another one... https://news.ycombinator.com/item?id=21741504
Re:How to write better game libraries by pjmlp on Monday December 09, 2019 @09:24AM (#21742864)
The difference being that my links have to do with damage C keeps bringing into IT and the respective monetary losses.

They are not random, only to those that don't care about improving the quality of our eco-system.

Software liability couldn't come soon enough.

Re:How to write better game libraries by jstimpfle on Monday December 09, 2019 @11:29AM (#21743927)
What do you think are the monetary losses by unmaintainable software, resulting in bad and extremely unsafe practices (not related to memory, but...) like in my link? What do you think are the monetary losses from developers going mentally ill because they don't understand and don't like the shit they're doing?
Re:How to write better game libraries by jstimpfle on Sunday December 08, 2019 @05:52AM (#21735306)
> Solved by C++ namespaces.

I've never understood what's the practical difference between NS::foo() and NS_foo() with regards to preventing name collisions. Can someone enlighten me?

I know some disadvantages of the namespacing variant, though. There are now multiple names for the items defined in the namespace: the qualified one and the unqualified one. The latter is often not unique in practice, since the programmer relies on the qualified name for uniqueness. In effect, making simple text searches for identifiers is very unreliable. Note I do use IDEs, but I also code in vim, and I need to do simple text searches even when working in Visual Studio.

Additionally, there's no guarantee that there are no spaces around the scoper. I believe "NS :: foo" is just as valid, which makes me uneasy with regards to text search, as well.

Another issue I have:

    $ cat test.cpp 
    namespace NS { int foo() { return 0; } };
    $ g++ -c -o test.o test.cpp
    $ nm test.o
    0000000000000000 T _ZN2NS3fooEv  # I hate my life
> Modern C++ has strongly-typed scoped enums for such constants.

I haven't found those working for me. Apart from the namespacing issue described above, I have issues with explicit enum types. One issue is that I often need to put sentinel / "missing" values (typically the value is -1) where an enum value is expected. Even more often, I want to iterate over the values of an enum. C++'s enum "type safety" makes working like this really unergonomic.

The way I go about this is I don't even use names for my enum types, and I fully qualify the enumeration values.

    enum {
        FPGAPARAM_BLA,
        FPGAPARAM_BLUB,
        FPGAPARAM_FOO,
        NUM_FPGAPARAM_KINDS
    };

    struct ASDF {
        int fpgaparamKind;   // obvious what kind of values are expected here...
    };

    for (int i = 0; i < NUM_FPGAPARAM_KINDS; i++) {
        struct ASDF asdf;
        asdf.fpgaParamKind = i;
        do_asdf(&asdf);
    }
In programming, the slightest mistakes, like putting a "-" instead of a "+", result in program bugs. These mistakes are much more likely to be made (and much harder to spot) than mistakes involving enum values from the wrong set. I won't let programming ergonomics be ruined in the name of "type safety".
Re:How to write better game libraries by Const-me on Sunday December 08, 2019 @06:17AM (#21735364)
> what's the practical difference between NS::foo() and NS_foo() with regards to preventing name collisions.

They both do the job. There’re 2 practical differences.

1. You can write `using namespace` inside functions or the whole .cpp files. This often makes the consuming code more readable.

2. Sometimes you want to replace implementations. With prefixes it gonna be massive changes likely to introduce new bugs. With namespaces, replace `using std::vector` with `using eastl::vector` and you’re done.

> Even more often, I want to iterate over the values of an enum.

I only need to do that rarely. When I do, I cast types like this:

    enum struct eParamKind : uint8_t
    {
        Bla, Blub, Foo, valuesCount
    };
    for( uint8_t i = 0; i < (uint8_t)eParamKind::valuesCount; i++ )
    {
        const eParamKind pk = (eParamKind)i;
        // Whatever
    }
> I won't let programming ergonomics be ruined in the name of "type safety".

I disagree on ergonomics. VS makes much easier to consume API with strongly typed enums: ePar<Ctrl+Space>::f<Enter>, to type eParamKind::Foo It’s similar with namespaces versus prefixes BTW, IDE will first auto-complete the namespace, then only list members of that namespace once you type the `::`

Update: another C++ feature relevant for game development is overloaded operators. Games often do non-trivial amount of math on small vectors, matrices and quaternions. Overloaded operators make sense for them.

Re:How to write better game libraries by jstimpfle on Sunday December 08, 2019 @06:31AM (#21735403)
Code completion works very well with plain identifiers. No need for namespaces.

> replace `using std::vector` with `using eastl::vector` and you’re done.

The pipe dream of reusability.. If I ever happen to be in a situation where that will work, I'll happily use a text replace to change my identifiers. Or just link a different library if it has the same names.

Re:How to write better game libraries by Const-me on Sunday December 08, 2019 @07:47AM (#21735629)
> Code completion works very well with plain identifiers.

It doesn’t on my PC.

I’ve copy-pasted C enum from your example, when I type FPG<Ctrl+Space> there’s no way to auto-complete just the FPGAPARAM_ part, to be able to then press F to get FPGAPARAM_FOO. Using VC2017 here, with latest Visual Assist.

Which C++ IDE are you using?

> The pipe dream of reusability.

Did it more than once.

Here’s one open source project where I’ve replaced most parts of the C++ standard library with EASTL: https://github.com/Const-me/vis_avs_dx

Here’s my header-only C++ library which allows users to switch between 16-bytes/32-bytes wide SIMD by using different C++ namespace, either Intrinsics::Sse or Intrinsics::Avx: https://github.com/Const-me/IntelIntrinsics/

Re:How to write better game libraries by jstimpfle on Sunday December 08, 2019 @01:30PM (#21737301)
I use VS at work, and I'm very happy with its code completions (except that the auto-popup behaviour is so unreliable or at least unintuitive. I'm sure there is an option to turn that off). I'm not aware of a way to complete to the largest prefix that is common to all completions, although something like that would be rather easy implement, too.
Re:How to write better game libraries by sharpneli on Sunday December 08, 2019 @04:35AM (#21735086)
And then there is things like windows.h defining max which breaks std::max. Sure that one has another define which prevents it but not all libraries have.

C++ defines don’t respect namespaces so you are pretty much screwed in anycase.

Re:How to write better game libraries by Const-me on Sunday December 08, 2019 @04:46AM (#21735117)
The OP’s advice to avoid macros in the library’s API is a good one. Please read my previous comments, it begins with “Some of these recommendations are awesome”.

BTW, you can disable these windows.h macros by defining NOMINMAX. I usually do, because I prefer min/max from <algorithm>; in some edge cases std::min / std::max can be twice as fast because compiler guarantees to compute arguments exactly once.

Re:How to write better game libraries by rehemiau on Sunday December 08, 2019 @05:18AM (#21735208)
C++ is not being used by all indie game developers so I imagine the article was written with that in mind, that the library needs to work with C code as well.