I write games in C (yes, C) (2016)
279 points
1 month ago
| 40 comments
| jonathanwhiting.com
| HN
torlok
1 month ago
[-]
I write mostly like I would in C, but use C++ features as needed. It ends up looking similar to Rust if you squint. All these "I write games in C" people complain about C++ features, and then end up reimplementing virtual interfaces manually with struct headers or massive switch statements, just to feel better about themselves. Writing games in C is not harder, you just have to implement modern language features by hand.

Complaining about a language having features you don't want is silly. C++ doesn't take longer to compile if you don't abuse templates.

reply
pron
1 month ago
[-]
> Complaining about a language having features you don't want is silly.

It might be silly if you're working on your own. Software that delivers a lot of value is usually developed and evolved not only by team, but by a team with changing members and changing leadership over the project's lifetime. The features used will be the union of all features used over the years, and while it's easy for team leads to allow the use of more features than their predecessors, it's quite hard to reduce them.

Also, you may be forced to use language features you don't want if they're used by libraries whose functionality you do want. For example, when doing low-level programming, I don't like implicit calls that I can't clearly see on the page (e.g. destructors or overloaded operators). But if libraries I want use them, then I'll have those implicit calls. But if the language doesn't have those features, libraries obviously won't use them.

reply
karamanolev
1 month ago
[-]
> It might be silly if you're working on your own.

That's exactly the case when it's easiest. If you don't need a feature, just don't use it and case closed. With a team it's harder - you have to force/enforce others not to use a given feature.

> if they're used by libraries whose functionality you do want

If you're using C++ you can just use the C library you would've used otherwise, no?

reply
adastra22
1 month ago
[-]
There are linters to do that enforcement automatically.
reply
Yokohiii
1 month ago
[-]
> Also, you may be forced to use language features you don't

This is quite important and often overlooked. An annoying fallacy is that people think some features are optional, but once they get heavily used, they aren't anymore. Often they quickly become an requirement and if you don't follow suit, your code is legacy or you are an idiot. But well, I guess I create legacy code upfront and the cargo cultists create modern code that turns into legacy next day.

reply
flohofwoe
1 month ago
[-]
> C++ doesn't take longer to compile if you don't abuse templates.

It actually does though, unless you also drop C++ stdlib usage completely (have you looked at how many lines of code just <vector> alone pulls into each source file? - it's upward of 20kloc and growing with each new C++ version).

And at that point you get into discussions with various C++ camps about why you don't use the C++ stdlib and instead prefer to reinvent the wheel (and this friction with other C++ coders is the main problem of carving out your own subset - it works ok in complete isolation, but software development work hardly happens in splendid isolation and even then you'd might to want to use C++ libraries written by other people from time to time...)

And once you've been dragged into such C++-subset-discussion month after month, year after year, at that point it is much less exhausting to just write plain C. And the C community (if it can be called that) seems to be much less concerned about coding style dogma and generally a nicer bunch to interact with.

FWIW, I switched around 2017 and each time I have to interact with a C++ library for lack of alternatives it's usually not a pleasant experience (with the notable exception of Dear ImGui - but even there I started to prefer the C bindings so that I don't need to strictly separate the UI code from the rest of the code base, which sometimes makes sense, but often not, especially with an immediate mode UI framework).

reply
tialaramex
1 month ago
[-]
> then end up reimplementing virtual interfaces manually

C++ dynamic dispatch (your "virtual interfaces") is achieved by welding a vtable onto every type and providing a pointer to that vtable for instances of the type. If in 90% of your code you deal with specific types like Goose or Swan or Duck or Seagull, and only 10% needs to work with the broad Bird category well, too bad, every Goose, Swan, Duck and Seagull carries around that vtable pointer even if it goes nowhere near that 10% of the system. This way your Bird code "just works" in C++.

That's not the only way to crack this nut. Idiomatic Rust approach uses vtables only in the Bird code, elsewhere they don't exist, and thus don't take up space in a Duck or whatever that's always a Duck, but in exchange now you're spending more time thinking, because by default there aren't any vtables and so dynamic dispatch isn't possible at all.

So while that C programmer has to implement features by hand, they are at least able to specifically implement the feature they wanted, not whatever was easiest for Bjarne Stroustrup last century.

reply
agentultra
1 month ago
[-]
C++ nudges you to think in terms of single elements. Operator overloading, ctors/dtors, references, etc. you pay that cost all over the place.

C programs tend to nudge you into thinking in terms of arrays of data.

For game development you generally want to think this way. The cost of vtables and all the cache misses doesn’t have to be paid. A game has to stream bytes. Many things at once. Rarely single elements at a time.

reply
pjmlp
1 month ago
[-]
Only if devs lack the skills to understand what to actually use.

There is this anti-C++ bias that keeps forgetting that using C++ doesn't mean use every feature.

Just like many keep using C as if C89 was latest, and never adopt anything added in the last 30 years.

reply
agentultra
1 month ago
[-]
I agree, there is a nice language buried in all the features trying to escape.

The struggle is that if you choose a subset of the language to use and you have dependencies… well you’re including whatever features they use into your subset.

I don’t think C++ is a bad language at all or anything. Just that it nudges developers into certain modes of thinking based on the features it chooses to focus on. Might explain why some developers still choose C.

reply
avadodin
1 month ago
[-]
What this comment looks like to a C programmer:

>> C89

> agree :D

reply
Panzerschrek
1 month ago
[-]
> by welding a vtable onto every type

It's not true. Virtual methods table is present only for classes with at least one virtual method. Learn C++ properly before doing such claims.

reply
tialaramex
1 month ago
[-]
The context you snipped is about dynamic dispatch, that is what you - as someone who has "learned C++ properly" apparently call "classes with at least one virtual method" and indeed the earlier comment calls "virtual interfaces".
reply
torlok
1 month ago
[-]
The convenience of having regular generics and dyn generics handled automatically is a great feature of Rust, sure, however you can write a template in C++ that directly calls a method, f.e. obj.Object::method(), which skips the vtable, achieving the same thing. Or you can keep manually writing everything in C because you refuse to learn C++.
reply
rramadass
1 month ago
[-]
Your example is disingenuous. What you are stating is the obvious trivial way of doing something when your objective is actually quite different.

You can get exactly what you are asking for in C++ using techniques of static polymorphism and CRTP pattern (https://en.wikipedia.org/wiki/Curiously_recurring_template_p... and https://en.wikipedia.org/wiki/Barton%E2%80%93Nackman_trick) along with traits and dynamic dispatch (if needed).

For great examples of the above, see the classic Scientific and Engineering C++: An Introduction with Advanced Techniques and Examples by Barton & Nackman (1994).

reply
saghm
1 month ago
[-]
What you're describing is needing to use specific verbose patterns to opt out of the defaults that do more complex things under the hood, whereas they're describing how C and Rust do not do those things by default and instead let you opt into them. It's not disingenuous to point that out.
reply
rramadass
1 month ago
[-]
Not quite.

What i am pointing out are neither complex nor any magic under-the-hood. They are simply techniques in the C++ repertoire well-known since the early 90's and used in all high-performance C++ libraries.

tialaramex made a big deal out of overheads in C++ dynamic dispatch (which incidentally are pretty minimal) using a trivial example, when performance focused (both time and size) C++ programmers do not use it that way at all. Modeling in C++ can be done in any number of ways and is driven by specific perspectives of the end goal.

reply
pjmlp
1 month ago
[-]
Except that C++ provides the tools to do just like C, Rust, or whatever one feels like doing for dispatching, even if it requires a few pages of template metaprogramming mixed with compile time executions, or writing exactly the same C code on the common subset across both languages.

Now with reflection even more tools will be available.

Which is why despite all its warts and security flaws, many inherited from C source code compatibility, many domains will keep using it, because they will complain about their missing 1% that no one else uses.

reply
tialaramex
1 month ago
[-]
Because these are General Purpose languages you can do the same things, but the contrast here is what's provided in the box and how it is used idiomatically, because in practice that's what gets used, and that's what I explained above.

You can write C++ style OOP hierarchy code in Rust but that's not idiomatic, and you can write Rust style explicit dynamic dispatch in C++ but again it isn't idiomatic.

reply
pjmlp
1 month ago
[-]
Microsoft uses Rust like traits on Windows with C++.
reply
petters
1 month ago
[-]
> C++ doesn't take longer to compile if you don't abuse templates.

Surprisingly, this is not true. I've written a C++ file only to realize at the end that I did not use any C++ features. Renaming the file to .c halved the compilation time.

reply
levodelellis
1 month ago
[-]
I don't believe you, I measured compile times in c compilers and my own. If you provide more information I'd be more likely to believe you
reply
flohofwoe
1 month ago
[-]
On some compiler toolchains (IIRC MSVC was the main offender) you get a lot more code pulled into your source file when including a C stdlib header (like <stdio.h>) in C++ mode versus C mode. Basically a couple hundred lines in C mode versus thousands of lines in C++ mode.
reply
petters
1 month ago
[-]
That's fair. I'm unable to provide more information though so we'll have to disagree.
reply
levodelellis
1 month ago
[-]
I measured once and to my surprise templates aren't (directly) the reason for long compile times. It's function bodies in headers, and obviously templates are in headers and they call other templated functions/classes which explodes code generation and time. But if it's only a few lines and doesn't call other templated functions it's likely fine. I wrote about it here https://bolinlang.com/wheres-my-compile-time

After writing that, I wrote my own standard library (it has data structs like vector, hashmap and sets; slices, strings, rng, print, some io functions, and more) which uses a lot of templates, and it compiles in <200ms on both clang and gcc. Many standard library headers take much longer to compile than that. It's not a terrible idea to have your own standard lib if you need quick compile times.

reply
rustyhancock
1 month ago
[-]
Another option can be if you have a core set of headers your project will use (and is stable) just precompiling them.
reply
direwolf20
1 month ago
[-]
Your website seems to be blocking Tor
reply
levodelellis
1 month ago
[-]
Oh? I use a boring old $5 VPS (using nginx for https). There's no cloudflare or anything else involved. I wonder why that's happening. I may look into that this week
reply
direwolf20
1 month ago
[-]
It could also just be down. I didn't try outside of Tor
reply
randomtoast
1 month ago
[-]
I’ve seen this play out a lot. People say they “write games in C” and then quietly rebuild half of C++ anyway with vtables in structs or giant switch statements, just without the compiler helping. That’s fine if it makes you happier, but it’s not obviously simpler or safer. Also, C++ compile times are mostly a self-inflicted wound via templates and metaprogramming, not some inherent tax you pay for having virtual functions.
reply
mjburgess
1 month ago
[-]
A switch statement is how you do ad-hoc polymorphism in C -- i dont thinks an own against C developers to point that out. If they wanted to adopt the C++ style that immediately requires the entire machinery of OOP, which is an incredibly heavy price to avoid a few switch statements in the tiny number of places ad-hoc poly is actually needed
reply
whizzter
1 month ago
[-]
You don't usually do C++ subsets if you want the full shebang.

I have a "mini-std" headerfile that's about 500 LoC implementing lightweight variants of std::vector, std::function, a stack-local std::function (unsafe as hell and useful as hell to avoid allocations), a shared-ptr, qsort and some other nifty stuff.

That does a lot of things, but even then I use other patterns that brings a lot of bang for the buck without having to go full C (hint: the stack-local function equivalent gets a lot of mileage).

reply
uecker
1 month ago
[-]
I think it is simpler and "the compiler not helping" == "things are more transparent".

  int a = 3;
  foo(a);
  // What value has a ?

There are various things one does not have to worry about when using C instead of C++. But the brain needs some time to get used to it.
reply
wasmperson
1 month ago
[-]
I think I get what you're trying to say, but you may have picked a bad example, here:

  #define foo(a) a = 12
reply
uecker
1 month ago
[-]
Yes, but this is more a theoretical problems while references are common in C++.
reply
sandpaper26
1 month ago
[-]
This reads like an LLM generated response that simply restates the comment it's replying to
reply
randomtoast
1 month ago
[-]
Heck the LLM accusations get a bit out of hand lately here on HN. I could delve into it now ... but I want to safe our time.
reply
gf000
1 month ago
[-]
> but it’s not obviously simpler or safer

On top of likely having worse performance.

reply
direwolf20
1 month ago
[-]
It's important that you do these things yourself before you utilise the compiler to do them for you, so you have real understanding.
reply
card_zero
1 month ago
[-]
C++ reimplements a lot of the things we do in C with function pointers, while hiding what's actually happening behind topheavy syntax that implies a 1990s object oriented paradigm that's dead now.
reply
direwolf20
1 month ago
[-]
Contrary to popular belief C++ isn't really object–oriented. I mean, you can write object–oriented code, but the language doesn't make assumptions about what goes into a class. It's really just a struct with associated functions.
reply
flohofwoe
1 month ago
[-]
> It's really just a struct with associated functions.

If that were actually true C++ would be a lot easier to accept as a 'C successor'. Instead you have the implicit this-pointer, complicated rules for which constructor or operator overload is actually called, a hidden vtable pointer (not to mention multiple inheritance), then you have public/private/protected, override vs final, const methods (which wouldn't be needed as a separate syntax feature if the this arg wouldn't be implicit) etc etc etc... that a lot of OOP-baggage which a lot of C++ coders probably don't even notice anymore.

A plain C struct with function pointers does indeed make a lot more sense than all the OOP-ism that C++ hides from you ;)

reply
direwolf20
1 month ago
[-]
It has lots of optional features, none of which make it an object–oriented language. It's an everything–oriented language. It has lambda syntax for functors, but you're not calling it an impure–functional programming language. Virtual functions are one feature, which is useful in pseudo–object–oriented code.
reply
Yokohiii
1 month ago
[-]
That's an odd opinion about a language with a lot of class related features. I can only assume you have a very strong definition of OOP.
reply
direwolf20
1 month ago
[-]
OOP doesn't mean that your language has a "class" keyword, nor dot notation for calling functions.
reply
afiori
1 month ago
[-]
I enjoyed the pragmatic historical definition of OOP given in https://www.youtube.com/watch?v=wo84LFzx5nI where essential it can be seen as subtype polymorphism
reply
vadersb
1 month ago
[-]
how is OOP dead if tons of code keep being written using OOP these days? From anything corporate in Java/C# to Hyprland C++
reply
pjmlp
1 month ago
[-]
What modern GUI in mainstream OSes isn't using OOP?

Have you bothered to look how GCC and clang are implemented?

reply
feelamee
1 month ago
[-]
Of course people do" virtual functions" in C, but I think this is not an argument despite C. I noticed that making virtual in C++ is sooo easy that people start abusing it. This making reading/understanding/debugging code much harder (especially if they mess this up with templates). And here C is a way - it allow but complicates "virtual". So, you will think twice before using it
reply
pjmlp
1 month ago
[-]
Most operating systems written in C have it all over the place.

Drivers, and extension points for userspace.

reply
feelamee
1 month ago
[-]
yes, but not soo much as my production C++. I know that that's our choice, but I underline the difference between C and C++ here
reply
lelanthran
1 month ago
[-]
> Complaining about a language having features you don't want is silly.

If your criteria for a good language is "how many features does it have", then sure, C++ wins. OTOH, if you criteria is "How many footguns does the language have" then C++ loses to almost every other mainstream language, which includes C.

Sometimes the lack of footguns is a plus.

reply
jamienicol
1 month ago
[-]
Surely your criteria should be some combination of the two (plus other factors). C may have fewer footguns than C++, but it still has many, whilst also lacking many useful features
reply
lelanthran
1 month ago
[-]
> Surely your criteria should be some combination of the two (plus other factors).

Sure, but the weighting would be different for different people.

> C may have fewer footguns than C++, but it still has many, whilst also lacking many useful features

We are not talking "2 fewer footguns", or "5 fewer footguns"; we are talking "dozens fewer footguns".

When I need a language with more features than C, I don't choose C++, because the choice is not "Use C for simplicity, and use C++ to trade simplicity off against features", it's usually "Use C for simplicity, and use Java/C#/Go/Rust for features".

reply
pansa2
1 month ago
[-]
Yeah, you could argue that choosing C is just choosing a particular subset of C++.

The main difference from choosing a different subset, e.g. “Google C++” (i.e. writing C++ according to the Google style guide), is that the compiler enforces that you stick to the subset.

reply
ninkendo
1 month ago
[-]
C's string handling is so abominably terrible that sometimes all people really need is "C with std::string".

Oh, and smart pointers too.

And hash maps.

Vectors too while we're at it.

I think that's it.

reply
WalterBright
1 month ago
[-]
When I developed D, a major priority was string handling. I was inspired by Basic, which had very straightforward, natural strings. The goal was to be as good as Basic strings.

And it wasn't hard to achieve. The idea was to use length delimited strings rather than 0 terminated. This meant that slices of strings being strings is a superpower. No more did one have to constantly allocate memory for a slice, and then keep track of that memory.

Length-delimited also super speeded string manipulation. One no longer had to scan a string to find its length. This is a big deal for memory caching.

Static strings are length delimited too, but also have a 0 at the end, which makes it easy to pass string literals to C functions like printf. And, of course, you can append a 0 to a string anytime.

reply
jfaulken
1 month ago
[-]
Just want to off-topic-nerd-out for a second and thank you for Empire.
reply
WalterBright
1 month ago
[-]
You're welcome!

One of the fun things about Empire is one isn't out to save humanity, but to conquer! Hahahaha.

BTW, one of my friends is using ClodCode to generate an Empire clone by feeding it the manual. Lots of fun!

reply
teo_zero
1 month ago
[-]
I agree on the former two (std::string and smart pointers) because they can't be nicely implemented without some help from the language itself.

The latter two (hash maps and vectors), though, are just compound data types that can be built on top of standard C. All it would need is to agree on a new common library, more modern than the one designed in the 70s.

reply
ninkendo
1 month ago
[-]
I think a vec is important for the same reason a string is… because being able to properly get the length, and standardized ways to push/pop from them that don’t require manual bounds checking and calls to realloc.

Hash maps are mostly only important because everyone ought to standardize on a way of hashing keys.

But I suppose they can both be “bring your own”… to me it’s more that these types are so fundamental and so “table stakes” that having one base implementation of them guaranteed by the language’s standard lib is important.

reply
uecker
1 month ago
[-]
why not std::string?
reply
teo_zero
1 month ago
[-]
You can surely create a std::string-like type in C, call it "newstring", and write functions that accept and return newstrings, and re-implement the whole standard library to work with newstrings, from printf() onwards. But you'll never have the comfort of newstring literals. The nice syntax with quotes is tied to zero-terminated strings. Of course you can litter your code with preprocessor macros, but it's inelegant and brittle.
reply
tialaramex
1 month ago
[-]
Because C wants to run on bare metal, an allocating type like C++ std::string (or Rust's String) isn't affordable for what you mean here.

I think you want the string slice reference type, what C++ called std::string_view and Rust calls &str. This type is just two facts about some text, where it is in memory and how long it is (or equivalently where it ends, storing the length is often in practice slightly faster in real machines so if you're making a new one do that)

In C++ this is maybe non-obvious because it took until 2020 for C++ to get this type - WG21 are crazy, but this is the type you actually want as a fundamental, not an allocating type like std::string.

Alternatively, if you're not yet ready to accept that all text should use UTF-8 encoding, -- and maybe C isn't ready for that yet - you don't want this type you just want byte slice references, Rust's &[u8] or C++ std::span<char>

reply
krapp
1 month ago
[-]
reply
pjmlp
1 month ago
[-]
If only WG14 added something similar to C.

Yes, SDS exists, however vocabulary types are quite relevant for adoption at scale.

reply
direwolf20
1 month ago
[-]
It's a class, so it doesn't work in C.
reply
uecker
1 month ago
[-]
Sure, but you can have a similar string abstraction in C. What would you miss? The overloaded operators?
reply
direwolf20
1 month ago
[-]
Automatic memory accounting — construct/copy/destruct. You can't abstract these in C. You always have to call i_copied_the_string(&string) after copying the string and you always have to call the_string_is_out_of_scope_now(&string) just before it goes out of scope
reply
uecker
1 month ago
[-]
This seems orthogonal to std::string. People who pick C do not want automatic memory management, but might want better strings.
reply
direwolf20
1 month ago
[-]
Automatic memory management is literally what makes them better
reply
uecker
1 month ago
[-]
For many string operations such as appending, inserting, overwriting etc. the memory management can be made automatic as well in C, and I think this is the main advantage. Just automatic free at scope end does not work (without extensions).
reply
direwolf20
1 month ago
[-]
You can make strings (or bignums or matrices) more convenient than the C default but you can never make them as convenient as ints, while in C++ you can.
reply
uecker
1 month ago
[-]
Yes, but I do not think this is a good thing. A programming language has to fulfill many requirements, and convenience for the programmer is not the most important.
reply
direwolf20
1 month ago
[-]
Empirically it is. All the most used languages are the most convenient ones.
reply
tialaramex
1 month ago
[-]
The C++ std::string is both very complicated mechanically and underspecified, which is why Raymond Chen's article about std::string has to explain three different types (one for each of the three popular C++ stdlib implementations) and still got some details wrong resulting in a cycle of corrections.

So that wouldn't really fit C very well and I'd suggest that Rust's String, which is essentially just Vec<u8> plus a promise that this is a UTF-8 encoded string, is closer.

reply
klaussilveira
1 month ago
[-]
reply
pjmlp
1 month ago
[-]
Yeah, WG14 has had enough time to provide safer alternatives for string and arrays in C, but that isn't a priority, apparently.
reply
9rx
1 month ago
[-]
Add concurrency and you more or less came up with same list C's own creator came up when he started working on a new language.
reply
saidinesh5
1 month ago
[-]
And constructors and destructors to be able to use those vectors and hash maps properly without worrying about memory leaks.

And const references.

And lambdas.

reply
pantalaimon
1 month ago
[-]
C is not a subset of C++, there are some subtle things you can do in C that are not valid C++
reply
pjmlp
1 month ago
[-]
It is when compared with C89, also the ISO C++ requires inclusion of ISO C standard library.

The differences are the usual that occur with guest languages, in this case the origin being UNIX and C at Bell Labs, eventually each platform goes its own merry way and compatibility slowly falls apart with newer versions.

In regards to C89 the main differences are struct and unions naming rules, () means void instead of anything goes, ?: precedent rules, implicit casts scenarios are reduced like from void pointers.

reply
uecker
1 month ago
[-]
Some subtle and some not so subtle.
reply
saidinesh5
1 month ago
[-]
Linters etc... Validates the subset you're choosing to use for your project too.
reply
krapp
1 month ago
[-]
>Writing games in C is not harder, you just have to implement modern language features by hand.

I feel like if you need to implement modern language features, you shouldn't be using C. The entire point of C is to not be modern.

reply
wasmperson
1 month ago
[-]
For every person who says on the internet that you can just use a C++ subset, there's another who insists that C is the bad C++ subset. So compiling C code with a C++ compiler promotes your code from "good C code" to "bad C++ code" (most C code isn't "exception safe," for example).

It's arguably irrational to evaluate a language based on this, but you can think of "this code could be better" as a sort of mild distraction. C++ is chock full of this kind of distraction.

reply
etrvic
1 month ago
[-]
I feel like, for me, it’s that I am more familiar with writing in C and switching to C++ seems rather difficult. So, sure I am reimplementing features that already exist in anoter language, it just so happens in this case is C++. Why not use python if you want to avoid reimplementing the wheel as much as possible. And sure python is not suited for game development but I just wanted to make a point with it. I think in the end ising a language you are most familiar with results in the most amount of enjoyable coding.
reply
cogman10
1 month ago
[-]
For a solo dev, it's not difficult. C++ is nearly a superset of C. You don't have to adopt all of C++ to start using it and to get immediate benefits from it (for example, unique_ptr, shared_ptr, and vector would all be things that I think any C dev would really appreciate).

A reason I can think of to not move to C++ is that it is a vast language and, if you are working on a team, it can be easy for team members ultimately forcing the whole team to become an expert in C++ simply because they all will be familiar with a different set of C++ features.

But for a solo dev? No reason not to use it, IMO. It's got a much nicer standard library with a rich set of datastructures that just make it easier to write correct code even if you keep a C style for everything.

reply
pjmlp
1 month ago
[-]
I learnt C++ on Turbo C++ 1.0 for MS-DOS as teenager, after doing C with Turbo C 2.0.

Being on Borland ecosystem that was followed by several years of Object Pascal (I was already using TP at the time), and C++.

Never got the point of why to keep using C, other than external constraints like school assignments, jobs requirements or lack of compilers.

reply
whizzter
1 month ago
[-]
Exactly, not even do you need to religiously need stick to your subset, separate modules can be using supetsets that import useful libraries and if they're used for code that is seldomly changed (such as model importers) then the longer compile time will only matter for rebuilds and not quick tests.
reply
HoldOnAMinute
1 month ago
[-]
It's possible to use only a subset of the language. You could write a Java program without classes if you really wanted to. Just put the whole thing in main().

A lot of smart people pick and choose what they want from the language, just like religion, they keep the good parts and discard the bad.

reply
direwolf20
1 month ago
[-]
main is also in a class in Java.

Even with the recent extension where it looks like it isn't, the compiler adds one for you.

reply
patrick451
1 month ago
[-]
At least you can read the switch statement. One of the worst features of c++ is all of the code that gets generated for you automatically.
reply
bobajeff
1 month ago
[-]
I remember the creator of Kaiju engine stating something about C++ compilers producing slower code with C-style C++.
reply
direwolf20
1 month ago
[-]
That's probably to do with exceptions — possibly the only thing that pervades C++ code even if you don't use it. The compiler has to write code so an exception at any point leaves the stack in a sensible way, etc. Try -fno-exceptions (and -fno-rtti might save some memory while you're at it)

Regrettably not every C++ feature is free if you don't use it. But there aren't many that aren't.

reply
Suppafly
1 month ago
[-]
>C is not harder, you just have to implement modern language features by hand

That's definitely harder.

reply
tomcam
1 month ago
[-]
> just to feel better about themselves.

Mindread much?

reply
pyrolistical
1 month ago
[-]
I always liked C. I enjoyed how brutal it is, except the preprocessor.

This is why zig is a godsend. It is actually simpler than C while being more precise than C!

For example zig can distinguish between a pointer to a single element vs a pointer to an array of unknown length. Where as in c abi, it is all T*

When importing a c lib, you can make it more ergonomic to use than c itself.

Being able to easily import c lib is especially important to game dev, as practically all so called c++ libs also export a c header as they know how important it is.

https://github.com/zig-gamedev has a lot of repos of ziggified c libs used in games.

As for the preprocessor, zig comptime is so much better. It’s just more zig that runs at compile time.

reply
dualogy
1 month ago
[-]
> as practically all so called c++ libs also export a c header as they know how important it is

In the gamedev space, I'd say too few of them do.

reply
vascocosta
1 month ago
[-]
I totally resonate with the author of the post. My main requirement to enjoy a language deeply is often simplicity, so I love languages like, C, Golang, Odin and Zig.

That said, I also acknowledge that often times I need to solve problems that can benefit from a language that embraces what I call necessary complexity, but do it in elegant ways. Whenever I need to prioritise code correctness, especially memory and concurrency safety, using a mostly functional pattern instead of OOP, but without going as extreme as say Haskell, I unquestionably choose Rust, my favourite complex language. I often work with network code that is highly concurrent, must be as correct as possible and benefits from good performance, so then again, Rust feels natural here.

On the other hand, I love coding simple indie games and for that particular case, I like a simple and performant language using an imperative, non-OOP style. In my opinion C, and in particular Odin more recently are quite a good fit. If Jonathan happens to be reading this comment, since he mentioned Golang, I would suggest him Odin as perhaps the best of both worlds between C and Golang. It has all the simplicity of Golang, but without a garbage collector, plus it is quite easy to code a game using Raylib.

reply
Zambyte
1 month ago
[-]
> I would suggest him Odin as perhaps the best of both worlds between C and Golang.

It's interesting to me that you say this, because it's the exact way that I describe Zig to people. Especially with the new std.Io async / concurrency changes. Do you feel Odin fits the space between Go and C better than Zig? Or just differently, and they both share the same space?

reply
pjmlp
1 month ago
[-]
The language is called Go, golang is the website domain.
reply
vascocosta
1 month ago
[-]
I know, but I often use Golang for two reasons: 1. avoids confusion, no matter how unlikely it is in a context like HN, and 2. search engine "findability".
reply
9rx
1 month ago
[-]
> 1. avoids confusion, no matter how unlikely it is in a context like HN

Who would be confused by "Go", but not "Rust" and "Zig", which are also common English words not usually associated with programming languages?

> 2. search engine "findability".

What kind of search engine are you using in 2026 that isn't capable of understanding context?

And where one is still using some weird antique thing like a steampunk character, "C" is going to be the least findable, yet it didn't receive the same treatment. Why is that?

reply
Melonai
1 month ago
[-]
At least with regards your second point, Google, DuckDuckGo, all other search engines. I always have to add "golang" because otherwise it just fucks up. I have to say that googling for "C", is a lot more dire, and because the LLVM people called their frontend "clang" I can't even use that, otherwise only clang stuff pops up. And even then, once I did manage to convince the search engine that I'm looking for the programming language, it still decides to just give me results for C++. It sucks.
reply
9rx
1 month ago
[-]
> I can't even use that, otherwise only clang stuff pops up.

The searchable form is 'clanglang'. golang is the language compiled by the go compiler, like erlanglang is compiled by the erlang compiler, and clanglang is compiled by the clang compiler.

reply
win311fwg
1 month ago
[-]
> because the LLVM people called their frontend "clang" I can't even use that

Said frontend is for the C programming language. Isn't that perfectly appropriate? I did a web search for "golang" and the first result was a download page for a Go compiler, so there is precedent.

reply
direwolf20
1 month ago
[-]
What's the first result for "clang"? How about in private browsing?
reply
win311fwg
1 month ago
[-]
A page about a C compiler. Not unlike the "golang" result, except without the same level of polish. The download link is similarly present, although due to the design choices doesn't stand out as the primary focus like it does in the "golang" case. I would consider the basic intent to be the same for both.

Which is the best one could hope for given that the search engine doesn't control the content. If I am searching for "golang", a Go compiler is the most likely thing I would want to find. Presumably someone who already has a Go compiler installed will have more specific queries. Likewise, if I am searching for "clang", a C compiler is also the most likely thing I would want to find. For all intents and purposes that is the entry point into using a language.

All in all the search engine did a great job and gave exactly what I would have expected.

reply
ternaryoperator
1 month ago
[-]
The use of "golang" for posts and comments is desirable IMHO because it greatly facilitates search, especially on sites such as HN that cover many languages.
reply
9rx
1 month ago
[-]
Searching "site:news.ycombinator.com go" on Google didn't yield any results that weren't about the Go programming language even after going several pages deep. What kind of search problems are you having, exactly?

And why is it unique to Go? I am sure there are comments on HN about metal oxidization, making sharp changes in direction, Norse gods, and letters of the alphabet.

reply
ternaryoperator
1 month ago
[-]
But if you go to the search box at the bottom of the HN page and type in 'go' the first hit is "Julian Assange has reached a plea deal with the U.S., allowing him to go free," In the top 10 results, only _two_ are about Go, the language.

Whereas the first 50 golang hits are all about the language.

You might have your preferred approach, but there are good reasons for using golang.

reply
9rx
1 month ago
[-]
> but there are good reasons for using golang.

Such as? If you type in 'C' into HN's search box, the first result is about the F.C.C., followed by C.E.O., then USB-C. Even once we finally see one about a programming language, it is about C#.

If the earlier list was instead 'Clangclang, Golang, Odinlang and Ziglang' then I could maybe understand where you are coming from, but that is not what we saw. Clearly there was no effort put into aiding searchers universally.

Are you trying to suggest that Go is the only language worth reading about? Let me try to restate the earlier question in your tongue: Why is it unique to 'golang'?

reply
pjmlp
1 month ago
[-]
I suggest admins to rename the post title as " I write games in Clang (yes Clang)", given how hard it is to find C content.

It might end up finding stuff about a compiler though.

reply
NewsaHackO
1 month ago
[-]
>Death of flash

>The library support for games[in Go] is quite poor, and though you can wrap C libs without much trouble, doing so adds a lot of busy work.

I can't see when this was written, but it has to be around 2015. So, about 10 years ago. I wonder what his opinion is today.

reply
QuantumNomad_
1 month ago
[-]
The first capture of the page on Internet Archive Wayback Machine is from January 9th, 2016. So it’s at least that old.

Also here is a snapshot of the main page of his website from that time, which has screenshots of his games and thereby provides context into what kind of games he had made and published when the blog post was written.

https://web.archive.org/web/20160110012902/http://jonathanwh...

This one looks like it’s 3d and has a pretty unique style:

https://web.archive.org/web/20160112060328/http://jonathanwh...

reply
edu
1 month ago
[-]
I think it would be aprópiate if @dang added a (2016) to the title
reply
akoluthic
1 month ago
[-]
It's not unheard of, but you have to be a little crazy to do this in 2026. I developed Chrysalis entirely in C (with GLFW3 and FMOD for audio): https://store.steampowered.com/app/1594210/Chrysalis/
reply
trueno
1 month ago
[-]
I've been working religiously for like 2 years on the jedi academy codebase which is c & c++. It's Ravensofts variant of the idtech3 engine and it's insane how fragile the games combat is to precision and timing changes, I can't get away with adding much without destroying the lightsaber combat qualities. There are certain spots where I can't even add an incrementing i++ counter lmao it presents just enough of a slowdown or shifts something around that I haven't been able to track down that bleeds into the rest of the gameplay, but I am also sticking with the ancient compilers from 22 years ago so as to preserve the fpu characteristics of the game. There are some modern attempts at using this codebase with modern tooling but they've kind of bastardized/refactored all of it and it just feels different/unbalanced wrong. idtech3 is such an incredibly foray into c it's really something else and carmack and team really sent it back in the day.
reply
lylejantzi3rd
1 month ago
[-]
Are you working on the original codebase or the OpenJK fork?
reply
trueno
1 month ago
[-]
original codebase
reply
agosz
1 month ago
[-]
If I may ask, how did you end up getting access to the code base? And what are you doing with it?
reply
trueno
1 month ago
[-]
ravensoft open sourced it in 2013 ish and promptly removed it because they accidentally included a bundled lib but i believe it was then re-added. theres quite a few repos that have it cloned. https://github.com/jedis/jediacademy

what am i up to with it? creating hardened vanilla base servers (no mods) and ensuring it gets compiled in a way that doesnt impact lightsaber combat. everyone has failed to do this for 22+ years because there's lots of subfactions in this game who fail to prioritize this as they have other priorities. tons of people who enjoy the prospect of modding the game or making it something different but the tiny remaining competitive player base has only ever needed the base game and what shipped by ravensoft in 2003. generally the guys who are competitive players arent.. coders. the game is ultra sensitive to mathematical FPU differences and virtually all recompiles of the game in the past decades completely failed to guard this, so every game mod and attempt at creating something better hasn't stuck for competitive players _except_ for something called ybeproxy which was an attempt to hook the original game engine binary and add some security/anticheat layer.. this was the best attempt to date but it still negatively impacts the fragile lightsaber mechanics.

reply
agosz
29 days ago
[-]
That's so cool! I didn't know they open sourced it. Is your work also open? And how do you check that the frames don't change?

I love seeing people try to revive old games and improve them for players. I've made a couple of contributions to VCMI, an open source implementation of heroes of might and magic 3 that I used to play as a kid and it's so rewarding seeing people use those.

reply
drnick1
1 month ago
[-]
Literally thousands of games have been written in C, and all graphics APIs (OpenGL, Vulkan, DX) are C APIs, so it isn't weird at all. All major game engines are also written in C/C++.
reply
jiggawatts
1 month ago
[-]
DirectX is C++ (technically a set of COM interfaces) and most game engines are also C++.

Unlike, say, Linux programming where C is the standard, almost all games have been written exclusively in C++ for a long time now, probably three decades.

reply
cedilla
1 month ago
[-]
There are a few exceptions though, like most mobile games, visual novels (many of which use Python of all languages, due to an excellent framework called ren'py), and of course games written using Unity or XNA, which use .NET languages.

Also, three decades is going a bit too far back, I think. In the mid nineties, C was still king, with assembly still hanging on. C++ was just one of several promising candidates, with some brave souls even trying Java.

reply
pjmlp
1 month ago
[-]
In J2ME feature phones Java was all there was, and even today many indies do use it on casual titles on Android.

Which is why after so much resistance not wanting to use the NDK for Vulkan, and keeping using OpenGL ES from those devs, Google is bringing WebGPU to Java and Kotlin devs on Android.

Announced at last Vulkanised, there is already an alpha version available, and they should talk more about it on upcoming Vulkanised.

reply
jiggawatts
1 month ago
[-]
> Also, three decades is going a bit too far back

My memory was wrong: I was thinking of the Quake 1 engine, but I just looked it up and it’s C with some assembly code, no C++. The reason I remember it being C++ was because Visual C++ was the compiler tooling required on Windows.

reply
direwolf20
1 month ago
[-]
COM was designed to be compatible with C. Linux games are also often written in C++. The ones written in C are just old.
reply
jiggawatts
1 month ago
[-]
Sure, but in practice COM is almost never used from C programs unless there is some integration into a very legacy codebase. Games are newly developed, they’re not enterprise database platforms.
reply
direwolf20
1 month ago
[-]
OpenGL is commonly used from C++ too, or Java, but you labeled it as C.
reply
lelanthran
1 month ago
[-]
> DirectX is C++ (technically a set of COM interfaces) and most game engines are also C++.

So? Their interface is via C, just like OpenGL was.

reply
pjmlp
1 month ago
[-]
Khronos APIs are C, DirectX is C++ exposed via COM or WinRT, Metal is Objective-C with C++ for shaders and Swift bindings, on Nintendo and PlayStation depends on which console generation you talk about.
reply
indy
1 month ago
[-]
Additionally SDL3 is also C and the most recent version of the Box2d physics library was rewritten in C
reply
Keyframe
1 month ago
[-]
In my core I'm the same. C is my language and served me well for decades. There's nothing inherently major wrong with it until you reach one of the two (or both). Working in a group of people on a C codebase tends to introduce pain on multiple levels unlike some other languages (yes, including C++). The other is that anything takes a long-ass time to do compared to modern alternatives, which might also be an issue if you're developing a game; Especially if you're developing a game. Having said that, I can't disagree since as I said, I'm also inclined towards it's siren call of simplicity.
reply
uecker
1 month ago
[-]
Why do you think working with a group of people on a C codebase introduces pain unlike other languages? Working with a group of people always causes pain, but I found the pain much less severe for C than for C++.
reply
direwolf20
1 month ago
[-]
C relies on the programmer to understand the lifetime of every object in the program, which is global structure. When the programmer is multiple people, it's easy to get out of sync. unique_ptr from C++ solves 90% of this.
reply
smallstepforman
1 month ago
[-]
Ever use a leak detector? Even my graphics engines (with shared resources) uses a leak detector in debug mode. The monent you forget to release a resource, assertion at program termination.

Leaks are trapped with tooling, and all you need is one dev in the team to be diligant to run valgrind or visual leak detector or similar.

reply
uecker
1 month ago
[-]
We run valgrind and asan as part of the CI, so it is checked before every merge and no developer has to be particularly diligent. But it is also not something that triggers a lot.
reply
direwolf20
1 month ago
[-]
Do you think the best way to avoid bugs is to thoroughly test your code, or does understanding the code while you write it also help?
reply
saidinesh5
1 month ago
[-]
It depends on what you're building with the language too.

For eg. In very embedded contexts where we were not using any big data structures like struct of strings, not doing any memory allocations etc... C might be easier to reason about than C++. (No hidden code paths). Just allocate something on the stack, pass the pointer to a function to do the computation, done.

In any desktop apis (gui, web servers etc..), where you deal with collections of objects, need to spin up thread pools and rely on results from the future etc... The standard library data structures (vectors, maps etc...) alone makes C++ code a lot more easy to read and review than C. When raw pointers are forbidden, Ownership of memory becomes very clear. Granted my opinion of desktop development comes mostly from very few libraries (Qt vs. Gtk, gstreamer's C API vs. C++ wrapper, http libraries etc...), but there are some problem domains for which C is just insufficient.

reply
Keyframe
1 month ago
[-]
Your question also hides an answer. You don't often get to chose a group of people you work with, and unlike projects that self-attract and self-distill ideal profile (like linux mentioned in sister comment), you're left with people usually not used to ye olde C idioms. With C++ it's a bit easier since it is more widespread and supports some of the idioms people get used through schools and other projects. Of course, projects (should) always dictate a certain discipline by different mechanisms, but if certain way of thinking isn't ingrained then it introduces just that much more pain to the communication layer between people.
reply
uecker
1 month ago
[-]
I would argue that is is much harder to find a group of C++ programmers who write a coherent style of C++. In C there is not nearly as much to decide. Note also that I am speaking from experience with both.
reply
dragonelite
1 month ago
[-]
In my mind using a simpler language should be less painful given there is less to argue about given syntax and versions etc. Take c# for example you have multiple ways to do the same sort of things.
reply
NuclearPM
1 month ago
[-]
> Having said that, I can't disagree since as I said, I'm also inclined towards

Say more with less.

reply
heliumtera
1 month ago
[-]
>Working in a group of people on a C codebase tends to introduce pain on multiple levels unlike some other languages

linux attracted 2,134 developers in 2025

that kinda weakens your argument a little bit

reply
Keyframe
1 month ago
[-]
It proves the argument as an outlier. I explained in another comment. You often don't have the luxury of selecting the group of people you work with and more often than not, especially these days, people aren't used to (C) way of thinking which just introduces more noise to the communication between people.
reply
jonahx
1 month ago
[-]
Maybe (and I like C, for the record), but it doesn't follow necessarily. It's possible most of those devs were attracted by "working on linux," and are putting up with the pain of collaborative C. I know there's a movement pushing for more Rust.
reply
tialaramex
1 month ago
[-]
I think the popularity of Rust for Linux is also in part a reflection of internal discontent with poorly documented and sometimes straight up poorly understood kernel internal APIs.

When a developer asks Can I Fizzle this Doodad? C is comfortable with the answer being "It'll definitely compile but whether it would work is complicated - ask the expert on Fizzling and the Doodad expert, and hope they give the same answer" but Rust wants the answer to be "Yes" or "No" or at the very least, "Here is some actual text explaining when that's fine"

Sometimes it really is hard work to figure this out but for a project as big as Linux even in those cases it's often worth doing that hard work, because you unlock something valuable for every non-expert contributor and Linux has a lot of those.

reply
smallstepforman
1 month ago
[-]
If Linus started his OS project in 2026, he might have chosen Zig instead of C.
reply
stephc_int13
1 month ago
[-]
"nobody does this"

Well, this should be reformulated a bit. Using C is not the norm, but it once was and many people are still using C to write games, myself included.

reply
IshKebab
1 month ago
[-]
When people say "nobody .." or "everybody .." they often - maybe even usually - do not literally mean 100.000000% of people. You are an outlier. He is still correct to say "nobody does this".
reply
quotemstr
1 month ago
[-]
> I like Go a lot. In many ways it is C revisited, taking into account what has be learnt in the long years since it was released. I would like to use it, but there are big roadblocks that prevent me. The stop-the-world garbage collection is a big pain for games, stopping the world is something you can't really afford to do.

I'm no Go fan, to be clear, but GC isn't the problem with Go. It has a pretty decent GC with sub-millisecond pause times. People who complain about GC pauses while extolling the virtues of manual memory management are running on a set of prejudices from 1999 and are badly in need of a mental firmware update.

reply
carefree-bob
1 month ago
[-]
The performance gains from bit-level control over memory come from managing the layout to ensure cache locality and do things like SIMD - and nowadays even GPU kernel offload. Enormous performance gains.

I agree that it really isn't about garbage collection pauses, but I haven't heard people focusing on "eliminating gc pause" when they talk about low level languages, but they spend a lot of time talking about SIMD, GPU kernels, and cache misses. If Go could add these features, it would be a performance monster.

reply
nasretdinov
1 month ago
[-]
Go defines structs the same way C does, so it's already encouraging thinking about and optimising the physical data layout. It also recently added experimental support for SIMD intristics: https://go.dev/doc/go1.26#simd . Nothing on GPU side yet though, but I wouldn't be surprised to see it there eventually too :)
reply
carefree-bob
1 month ago
[-]
Yes, I know Go's structs are similar to C in terms of syntax, but does the Go compiler guarantee the same bitwise layout for its data structures? Most GC languages add metadata to the data structures to track GC status, and this changes both the memory layout and the word alignment, which then sometimes forces the language to add extra padding to maintain alignment. And this nests as you put one struct inside another, or an array inside a struct.

Now you have "fat arrays" and "fat structs", so instead of grabbing a pointer and loading the next 128 bits into memory and doing an operation, you have to grab the pointer, read out data from individual elements, combine them, create a new element with the combined data, and then you have a 128 bits. But even then, you don't know whether you have 128 bits or not. Some gc-specific metadata might have been added by the compiler (and probably was).

Bottom line, it's very hard in the GC world to have bit-wise control over memory layout, even if user-level syntax of "structs" is the same. And one consequence of that is that you can't just "do" SIMD in Go. You have to wait for Go to expose a library that does this for you, and you will always be limited by what types of unpacking/repacking the language designers allowed you to do.

Or, you are stuck with hoping the compiler is very smart, which is never the case and requires huge compile times for marginal gains in compiler smarts.

So it's not about GC collection pauses so much as no longer having access to memory layouts.

reply
nasretdinov
1 month ago
[-]
> does the Go compiler guarantee the same bitwise layout for its data structures

It probably won't be fully 1:1 with C, but it's good enough that you can write code like this and it works: https://github.com/fsnotify/fsnotify/blob/main/backend_inoti... (unix.InotifyEvent is just a Go struct: https://pkg.go.dev/golang.org/x/sys/unix#InotifyEvent)

> Now you have "fat arrays" and "fat structs", so instead of grabbing a pointer and loading the next 128 bits into memory and doing an operation, you have to grab the pointer, read out data from individual elements, combine them, create a new element with the combined data, and then you have a 128 bits.

That is not how it works, you get real pointers that you can even do math with using unsafe package.

> Most GC languages add metadata to the data structures to track GC status, and this changes both the memory layout and the word alignment, which then sometimes forces the language to add extra padding to maintain alignment

Go GC uses a separate memory region to track GC metadata. It does not embed this information into structs, arrays, etc, directly.

> And one consequence of that is that you can't just "do" SIMD in Go. You have to wait for Go to expose a library that does this for you, and you will always be limited by what types of unpacking/repacking the language designers allowed you to do.

You very much could, thanks to what I described above. You'll have to write assembly (Go supports assembly), and it's even used in some e.g. crypto libraries not just for performance reasons, but to ensure constany-time operation too.

The downside of using assembly is that it doesn't support inlining, and there's a small shim to keep ABI backwards compatible with the original way functions were called (using stack, whereas newer ABI uses registers). So you need to write loops in assembly too to eliminate the function call overhead. The SIMD package solves this issue by allowing code inlining.

reply
carefree-bob
1 month ago
[-]
> Go GC uses a separate memory region to track GC metadata. It does not embed this information into structs, arrays, etc, directly.

I didn't know this, thank you. That's a solid approach.

reply
nasretdinov
1 month ago
[-]
Yeah I was a bit surprised by this too. I think the post was written around 10 years ago, when it still was a genuine problem in Go.
reply
quotemstr
1 month ago
[-]
Good eye. This is why HN titles have year tags. :-)

Yeah, this is from 2016. I don't think choosing C over C++ was defensible even back then, but the critique of Go makes more sense now.

https://web.archive.org/web/20160109171250/http://jonathanwh...

reply
Bengalilol
1 month ago
[-]
I did read the whole article thinking "who is he, his name reminds me something, but why isn't he providing game names?" and so on. Then I clicked on "back to main site". Revelation. A lot of his games are jewels. I have a special thing/relation with Sportsfriends. So many hours of fun while playing with my son.
reply
smallstepforman
1 month ago
[-]
Noble quest, but without operator overloading when dealing with Matrix*Vector you end up with an unreadable mess for physics, skeletal animation etc. There is a reason professional game dev is still 90% C++. (Funny enough, amateur gamedev is C# these days, students use what they learn at uni).
reply
nurettin
1 month ago
[-]
Funny enough, amateur gamedev using C# is a billion USD industry.
reply
krapp
1 month ago
[-]
... because that's what ships with Unity.
reply
teunispeters
1 month ago
[-]
I like C. You can take away all memory management (yes, including some of the unsafe glibc calls that have hidden memory management) and everything can be so smooth and clean. Since rules like MISRA require up-front allocation - if any is in use - this can be tightly controlled.

Very useful if you don't want (or need) surprises anywhere. Or if you want all the surprises (exceptions, errors, etc) all better tied to the hardware that provides such.

It's also fairly easy to write unit tests for everything.

reply
p0w3n3d
1 month ago
[-]
C has very low entry level, providing that you have some knowledge about memory management. When, as a Java developer, I had to quickly deliver some exchange connector using given .h and .so, I chose C, because C++ had too high entry level. If C is a sharp knife, C++ is a rotating pell post full of sharp knives. You can cut yourself even if you think you're safe.

But I find string management in C awful and would like to borrow it from C++. Only the string management

reply
direwolf20
1 month ago
[-]
That's the neat thing about C++. You don't have to use any of it that you don't want to.
reply
IshKebab
1 month ago
[-]
That's only really true for solo projects. For example I worked in a company on a C++ SDK for a while and it was written by one of those clever people who has zero taste in software development and thinks you have to use GoF patterns everywhere. The god object was a CRTP inheriting from about 20 templated base classes.

I spent about a year trying to sort out that mess and then quit.

To be clear I would still always pick C++ over C because C makes simple stuff (strings and containers mainly) waaaay more painful than they should be. But I also don't really agree with the "C++ is simple - just don't use the complex bits!" argument.

Anyway it's kind of academic now because 99% of the time Zig is an obviously better choice than C and Rust is an obviously better choice than C++.

reply
JamesTRexx
1 month ago
[-]
I'm pulling apart and rewriting so far a little in C a personal fork of OpenTTD 12.2. I began on it a few years ago for the first time for the heck of it after patching for realtime, began again while adding features I wanted until I hit a bad enough snag, and now began again by first extracting most used functions and profiling with Valgrind inbetween.

Things I noticed are inconsistent coding styles, overly complex processes, unused(!) functions, inefficient data use, nothing surprising with a project worked on by various people in their spare time and their own ideas on how to code. And this isn't even talking about later versions. To me it's an example of how unrestricted access to bling features causes a mess.

Eventually I want it converted to C (C23), split apart in seperate functions with a decent source code organisation, and simplified processes to make it easier to understand what's going on and extend fuctionality. For this I need it simplified as possible and weed out the layer of complexity caused by C++ first. Going to take plenty of time, but I'm still having fun doing it (most of the time anyway :-p ).

I'm not advocating anything, but it's satifying to me to bring clarity to code and see small improvements to performance during the process at the same time. It also gave me an opportunity to develop a unique syntax style that visualises parts of the code better for me.

reply
uecker
1 month ago
[-]
This is great! This so rare that people remove the complexity again that has accumulated over the years. Most of the programming world is just accumulating entropy and then people give up and start fresh at some point, which is just sad.
reply
guerrilla
1 month ago
[-]
As a hardcore C programmer and zealot myself... How in the hell can you be productive like that? C is a systems programming language, not an application programming language, let alone relevant to the levels of abstraction you'd want in game development.

That said, "I am dead" is a very real video game indeed... and his arguments are very sound. I also can't stand C++. I disagree with him on Java though. The core language of Java is actually super simple, like C.

reply
tuhgdetzhh
1 month ago
[-]
I think the productivity question hinges on what you count as the language versus the ecosystem. Very few nontrivial games are written in "just C". They are written in C plus a large pile of bespoke libraries, code generators, asset pipelines, and domain-specific conventions. At that point C is basically a portable assembly language with a decent macro system, and the abstraction lives outside the language. That can work if you have strong architectural discipline and are willing to pay the upfront cost. Most teams are not.

I agree on C++ being the worst of both worlds for many people. You get abstraction, but also an enormous semantic surface area and footguns everywhere. Java is interesting because the core language is indeed small and boring in a good way, much closer to C than people admit. The productivity gains mostly come from the standard library, GC, and tooling rather than clever language features. For games, the real disagreement is usually about who controls allocation, lifetime, and performance cliffs, not syntax.

reply
guerrilla
1 month ago
[-]
> I agree on C++ being the worst of both worlds for many people. You get abstraction, but also an enormous semantic surface area and footguns everywhere.

Not only that, but who even knows C++? It keeps changing. Every few years "standard practice" is completely different. Such a waste of energy.

> Java is interesting because the core language is indeed small and boring in a good way, much closer to C than people admit.

I know. I used to be a Java hater, but then I learned it and it's alright... except the whole no-unsigned-integers thing. That still bothers me but it's just aesthetic really.

reply
nayuki
1 month ago
[-]
> no-unsigned-integers [...] still bothers me

I like the lack of unsigned integers in Java. It simplifies the language while only removing a tiny bit of functionality. You can emulate almost all unsigned math using signed operations, whether you use a wider bit width or even the same bit width. The only really tricky operations are unsigned division and unsigned parseInt()/toString(), which Java 8 added to smooth things over.

https://www.nayuki.io/page/unsigned-int-considered-harmful-f...

reply
1718627440
1 month ago
[-]
The reason for using unsigned is not that some operations need it, it is so to declare a variable that can't be negative. If you don't have that, then you must check for a negative number in every single interface.
reply
direwolf20
1 month ago
[-]
You have to try it. You can write anything you want in C. Or assembler. It's hardly going to be very productive but... productivity is greater than zero, and the more you try the better you get. Rollercoaster Tycoon was written by hand in assembly, as were all NES and SNES games including ones like Earthbound and A Link to the Past — and SNES assembly isn't nearly as nice as x64.
reply
uecker
1 month ago
[-]
Ah, the C++ guy who think you need all the features of C++ to be efficient... Many people of people are super productive in C. There is a cost, but this is usually just some initial overhead to identify / write some libraries. In a larger project this initial overhead is irrelevant.
reply
direwolf20
1 month ago
[-]
If someone is using a C++ feature it's because they think the feature is better than not using it. std::string lets you treat strings as easily as ints — subject to a run–time cost. You can make libraries that make strings easier to use in C, but you can't make one that makes them as easy as ints.
reply
uecker
1 month ago
[-]
But it does not have to be "as easy as int" to be able to be productive in C. Almost as easy is sufficient.
reply
direwolf20
1 month ago
[-]
It's not almost.
reply
uecker
1 month ago
[-]
I am very happy with my string type in C.
reply
Andrex
1 month ago
[-]
> The core language of Java is actually super simple, like C.

Not being facetious, but couldn't you say that about almost any language? What makes you say it about Java?

reply
direwolf20
1 month ago
[-]
I'm not sure you could say it about C++, Scala (Java's C++) or Rust?
reply
giancarlostoro
1 month ago
[-]
Were not most games back in the day in C?
reply
guerrilla
1 month ago
[-]
Back in what day? Quake II I would say is the best good looking thing written in pure C. id Tech 3 is partly C++. Everything after that era was pretty much C++. Even GoldSrc is partly C++. Source was pure C++.
reply
giancarlostoro
1 month ago
[-]
I guess back in my day, early to mid 90s. My understanding is C became more common.
reply
guerrilla
1 month ago
[-]
Well I guess that was my time too but it was kind of a very short period. We went from assembly to C++ pretty quickly. Like things were assembly for a very long time, and they have been C++ for a very long time, but C was dominant mostly in that Doom to Quake II window.
reply
bowsamic
1 month ago
[-]
Most games back in the day were written in assembly
reply
pantalaimon
1 month ago
[-]
Quake and Doom sure come to mind
reply
ddtaylor
1 month ago
[-]
I need RAII and refuse to debug ugly macros as a workaround. The STL isn't perfect but it's a good guiding principle.
reply
csb6
1 month ago
[-]
Yes, having built-in generic containers and algorithms is the part that keeps me favoring C++. Bespoke versions of these can always be written in C (and work fine) but C++ makes it much easier and saves time. Lambdas and function objects are also useful.
reply
direwolf20
1 month ago
[-]
You should try writing something serious in C just for the hell of it. And without RAII-like macros. Write all your allocs and frees.
reply
ddtaylor
1 month ago
[-]
I very much have. I specifically like to craft ISAs for genetic algorithms over the last two decades. It's not work I publish because I never feel like it matters, although I regret that often. I very much enjoy writing C for this purpose in many ways and I actually enjoy some of the allowances that fit very well to writing an ISA where every bit of the instruction must map to valid behavior and nothing can be an invalid instruction.

It's an ongoing struggle!

reply
leecommamichael
1 month ago
[-]
Come try Odin!
reply
doublerabbit
1 month ago
[-]
I've been doing theory and really want to myself.

Time escapes me before I get a chance to type Hello World. Working in front of a screen eight hours a day leaves me exhausted that the least things I want to do is code more on my day off.

Although wanting to dive in to WASM has been a priority and checking Odin for wasm their 3D model example is super cool.

May just have to take a poke. TCL for web frontend; Erlang for DB and potentially Odin for wasm? This could be a cool mix.

reply
andai
1 month ago
[-]
+1 for Odin

Did a bit of game dev in Odin last year and it was a wonderful experience. It's very much game dev oriented and comes batteries included with many useful libraries. And the built in vector stuff is very helpful there too.

reply
pjmlp
1 month ago
[-]
People did do that, 30 years ago.

Then Watcom C/C++ made it quite easy to use C++ for game development on PCs, PlayStation 2 introduced support for C++, quickly followed up by XBox and Nintendo, and that was it.

reply
kahlonel
1 month ago
[-]
Wrong. I’m still doing it.
reply
pjmlp
1 month ago
[-]
Linux kernel also keeps using C.
reply
zzo38computer
1 month ago
[-]
I also use C, for games and other stuff. However, for many games it can be useful to have a game engine, which is written in C (and I might write it by myself) but other parts will be written in the game engine. I also sometimes program games on DOS, and will use BASIC or Pascal. You will then not need to have too many dependencies; if it is a DOS program then the executable file should just work (with emulation if necessary) without the mess that is common on modern computers.
reply
HeavyStorm
1 month ago
[-]
Yes, C. Like all id games up to... Doom 3, if I'm not mistaken? Only then they switched to C++. There's absolutely nothing impressive about this fact.
reply
brokencode
1 month ago
[-]
Nobody claimed it was impressive. It’s a little unusual to use C instead of C++, but that’s about it.
reply
direwolf20
1 month ago
[-]
It's impressive these days when software quality and craftsmanship is declining.
reply
andreldm
1 month ago
[-]
I was also really surprised with Haxe, I share the author’s concerns about its future, other than it’s quite fun to work with.
reply
dismalaf
1 month ago
[-]
Haxe is a great language but it feels like the ecosystem has been stagnant for 10 years. No Vulkan bindings, no SDL3, still trying to be a web language that happens to compile to native code instead of getting with the times and going fully native + maybe wasm. Part of me wants to write my own bindings to SDL3 in Haxe but it's far easier to just use Odin these days.
reply
Mikhail_Edoshin
1 month ago
[-]
I want to write general apps in C. Such as a raster image editor. I have some idea and C has exactly the right mix of simplicity and flexibility that I need. C is a constructor, and as a constructor it places few limits on what you can do. Other environments are way more rigid. E. g. I find Python way too rigid compared to C.
reply
seabrookmx
1 month ago
[-]
GTK apps can be written in pure C. GTK itself is.
reply
andreamonaco
1 month ago
[-]
I fully agree, in fact I'm writing a game in C too, it's https://github.com/andreamonaco/zombieland. Plus I have at least another idea for a game project in mind with the same language.
reply
webdevver
1 month ago
[-]
its funny how writing games in C is now seen as some kind of 'hardcore mode', despite the fact that a huge number of excellent titles up to and including the 2000s were written that way.

the core of games tend to be a 'world sim' of sorts, with a special case for when a select entity within the world sim gets its inputs from the user.

where C becomes a chore is the UI, probably has to do with how theres many more degrees of freedom (both in terms of possibilities and what humans consider appealing) in the visual plane than there is in the game input 'plane', which might be as little as 6 independent inputs plus time.

reply
namuol
1 month ago
[-]
reply
pansa2
1 month ago
[-]
There’s also CimGUI. I know the underlying C++ library is well-regarded - I’m curious to hear people’s experiences using the C wrapper.

https://github.com/cimgui/cimgui

reply
pengaru
1 month ago
[-]
For quite some time even games technically written in C++ were more appropriately described as C compiled by a C++ toolchain with a minimum of actual C++ syntax - more like C with classes.
reply
glimshe
1 month ago
[-]
Rollercoaster Tycoon was written in assembly! C was easy mode back in the day...
reply
howToTestFE
1 month ago
[-]
Has anyone got any good resources for something like this? I haven't touched C in years, and never worked on anything game-like. But it does look like a really interesting project to start something like this.
reply
lylejantzi3rd
1 month ago
[-]
If you have patience, the first 30 or so episodes of Handmade Hero are pretty good.

https://guide.handmadehero.org/code/

reply
krapp
1 month ago
[-]
Handmade Hero is a bad idea for anyone wanting to learn how to make a game in C or C++. Casey intentionally avoids using standard libraries and frameworks and his irrational hatred of high-level code and modern standards will lead developers astray and waste their time.

Even if you're using C you don't need to implement your own renderer or do half the things he does. Get a library like SDL3 to handle the basics, maybe use Lua/LuaJIT for scripting. Learn OpenGL or Vulkan. Stay away from HH and Casey Muratori until you're experienced enough to tell the difference between his wisdom and his bullshit.

reply
lylejantzi3rd
1 month ago
[-]
We'll have to agree to disagree on this one.
reply
anatoly
1 month ago
[-]
raylib is one possible starting place. Also might look at dos-like (https://mattiasgustavsson.itch.io/dos-like).
reply
quotemstr
1 month ago
[-]
Plenty of people cycle on a fixie too. So what? C, especially modern C, does provide metaprogramming and abstraction facilities. In practice, you can even get things like the "defer" construct from other languages: https://lwn.net/Articles/934679/

The question isn't "Can I write a game in C?". Yes, of course you can, and it's not even that painful. The question is "Why would you?", and then "Why would you brag about it?"

> C++ covers my needs, but fails my wants badly. It is desperately complicated. Despite decent tooling it's easy to create insidious bugs. It is also slow to compile compared to C. It is high performance, and it offers features that C doesn't have; but features I don't want, and at a great complexity cost.

C++ is, practically speaking, a superset of C. It being "complicated"? The "insidious bugs"? It being "slow to compile"? All self-inflicted problems. The author of this article can't even fall back on the "well, my team will use all the fancy features if I let them use C++ at all!" argument pro-C-over-C++ people often lean on: he's the sole author of his projects! If he doesn't want to do template metaprogramming, he... just doesn't want to do it.

I don't read these sorts of article as technical position papers. People say, out loud, "I use C and not C++" to say something about themselves. ISTM that certain circles there's this perception that C is somehow more hardcore. Nah. Nobody's impressed by using it over a modern language. It really is like a fixie bicycle.

reply
wudangmonk
1 month ago
[-]
If he doesn't use C++ features then there's no point of bothering with C++ at all. C++ is kinda but not really a superset of C. There are some nice features that are lacking in C++.

The fixie example wants to make the comparison that using C instead of C++ is deliverately done just to brag about doing something in a way that is more difficult than in should be. In reality the issue is that C++ might not offer you any benefit at all and it could potentially bring you issues later on for things such as interfacing with other languages.

I personally do not see the point of using C++ if you do not use any of its features.

reply
direwolf20
1 month ago
[-]
Usually you start with just one feature, like std::map instead of OpenSSL's abomination of a hashmap library or rolling your own.

Of course you should use std::unordered_map instead of std::map because the latter is actually a treemap, but you probably don't know that when you first learn it...

reply
its_magic
1 month ago
[-]
Nah, I prefer to just use C, because at least I can parse the quite sane and helpful error diagnostics when I omit a semicolon or something, instead of getting 15 pages of unreadable garbage dumped into my lap by the oh-so-wonderful C++ standard library.

(Which quite frankly isn't much of a "standard" when there's about a dozen different real world interpretations of the code depending on which flavor of which compiler from which year that you're using.)

I also don't have to wait eons for my code to compile. Really, the mental and computational load of C has got to be 1/10 of C++.

What a nightmare C++ is, and it just keeps getting worse every year thanks to the incompetent standards committee.

reply
direwolf20
1 month ago
[-]
LPT: scroll up to the top of the error message. Typically it's "could not match this function call" followed by "here's all the things that might match and why they don't match"
reply
lelanthran
1 month ago
[-]
> People say, out loud, "I use C and not C++" to say something about themselves. ISTM that certain circles there's this perception that C is somehow more hardcore.

Sounds like this is just you projecting.

Almost any language has fewer footguns than C++, and thus programmers will take almost anything else over C++.

It's just incidental that "anything else" also includes C.

reply
enricotr
1 month ago
[-]
"Practically speaking" means nothing. Use "from my confused point of view", instead.
reply
quotemstr
1 month ago
[-]
If GDB could switch its C codebase to compiling as C++ without major surgery, it's close enough.
reply
its_magic
1 month ago
[-]
> I don't read these sorts of article as technical position papers.

I do.

> People say, out loud, "I use C and not C++" to say something about themselves.

Just like you are telling us something about yourself right now.

> ISTM that certain circles there's this perception that C is somehow more hardcore.

That's not why we use it.

There are certainly many noobs who think C is hardcore. That just goes to show how low the bar has fallen since the masses rushed into computing.

Many of these people also think of changing their own oil or a flat tire as being a superpower. Some could not identify the business end of a screwdriver if their life depended on it. Their opinion on the relatively difficulty or impressiveness of anything is to be taken with a huge grain of salt.

There are many good reasons to use C. If nothing else it demonstrates that the user is a free thinker and not a fucking muppet. It's the sort of thing that attracts me and drives you away. That's valuable.

> Nobody's impressed by using it over a modern language.

1) The word "modern" is not a magic talisman that makes anything it's attached to automatically worthy.

2) "Nobody" does not mean what you apparently think it means. Free clue: others exist in the world beside yourself and your self-absorbed clique.

3) Nobody with a brain is impressed by whatever the midwits are doing. Anyone who can fog a mirror can follow the herd off the nearest cliff. It's the outliers who are impressive.

4) Technically anything since the 1500s is "modern." It's such a vague, useless word that serves no purpose other than "virtue" signalling.

C++ is fucking garbage. Always has been. Keeps getting worse and worse every year. Enjoy your PAGES full of indecipherable gibberish ("error diagnostics"), your miserably slow compile times, and your closet full of footguns and decades old sticks of sweating dynamite. Slowest language by far, other than the so very modern abomination that is Rust. You can keep it.

reply
tombert
1 month ago
[-]
I've been writing a good chunk of C lately for some stuff that has some relatively high memory constraints (lower than I could squeeze out of GraalVM).

I know I could do C++, and you could argue that's better, but I find C++ to be exceptionally irritating to use. Every time I've used C++ I get people telling me I'm using it "wrong", sometimes in contradictory ways. Sometimes I should use a "friend" function, sometimes "friend functions are evil". Sometimes multiple inheritance is fine, sometimes it should be avoided like the plague. Sometimes you should "obviously" use operator overloading, sometimes you should avoid it because it's confusing because you don't know which functions are being called.

I'm sure someone here can "educate" me with the best practices for C++, and maybe there will be some reasoning for it, but ultimately I don't really care. I just found the language annoying and I don't enjoy using it. I know that I could "just write it mostly like C and use the C++ features when I need it", but I have just found that I have more fun thinking in pure C, and I've kind of grown to enjoy the lack of features.

Maybe it's just a little bit of masochism on my end, but I like the fact that C gives you so little. You kind of have to think about your problem at a very fundamental and low level; you have to be aware of how memory is allocated and deallocated, you don't get all these sexy helper functional-programming constructs, strings aren't these simple automatic dynamic things that you have in basically every other language. You have a dumb, simple language that will give you exactly what you need to write programs and very little else.

Most stuff I write uses a garbage collector, but the safety and easy of writing stuff with garbage collectors like Java makes it very easy to be lazy. I've grown to appreciate how much C makes you actually think about problems.

reply
rramadass
1 month ago
[-]
> I know I could do C++, and you could argue that's better, but I find C++ to be exceptionally irritating to use. Every time I've used C++ I get people telling me I'm using it "wrong", sometimes in contradictory ways. Sometimes I should use a "friend" function, sometimes "friend functions are evil". Sometimes multiple inheritance is fine, sometimes it should be avoided like the plague. Sometimes you should "obviously" use operator overloading, sometimes you should avoid it because it's confusing because you don't know which functions are being called.

That is because you are looking at Design in C++ wrong. Language features and low-level abstractions are just mechanisms. You have to put them into a coherent framework for modeling a problem domain via commonality & variability analysis (aka domain engineering) onto a solution domain consisting of language features, idioms and patterns.

For a very good explanation, see the classic book, Multi-Paradigm Design for C++ by James Coplien.

The above can also be found in his PhD thesis Multi-Paradigm Design available in pdf form here - https://tobeagile.com/wp-content/uploads/2011/12/CoplienThes...

reply
cyh555
1 month ago
[-]
I read this article years ago and haven't been able to find it since. It's a pleasant surprise to come across it here.
reply
parasti
1 month ago
[-]
What does "vanilla C" mean? Asking as a maintainer of 20 years of a game written in C.
reply
graemep
1 month ago
[-]
> when it comes to compilation I can't think of anything faster.

What languages compile fastest?

reply
levodelellis
1 month ago
[-]
IIRC go wasn't that fast but can feel like it in vscode. IIRC vscode compiles go using the lsp which is faster than launching a process because for some reason, vscode stalls for a second or more before launching a process.

I can't remember how fast D was but iirc it was fairly fast. Actual fastest is my compiler which I don't work on anymore and isn't ready for production. It's the only compiler I know of that hit millions of lines <1s in a non trivial language https://bolinlang.com/

reply
tmtvl
1 month ago
[-]
Not every compiled language has a de facto standard compiler, but with SBCL Common Lisp compiles pretty quickly. The Pascals (and Delphi) also tend to have rather fast compile times. I believe Jai is supposed to compile quickly but I'm not in the beta so I don't know. C can be quite good if you know what you're doing and use a decent compiler.
reply
graemep
1 month ago
[-]
I should really have specified fast compiling implementations.

It does make me wonder why Pascal never became more popular. Fast compiling is a big advantage.

reply
gfody
1 month ago
[-]
nothings faster than turbo pascal
reply
elcritch
1 month ago
[-]
Nim compiles fast.
reply
arcologies1985
1 month ago
[-]
Rust can be up there with C depending on the project.
reply
NewsaHackO
1 month ago
[-]
is that a joke?
reply
enricotr
1 month ago
[-]
Any language can be, depending on the project. Rust compile is slower than C, on more than average. That's it.
reply
mapcars
1 month ago
[-]
>I really dislike javascript, it is so loose that I marvel that people are able to write big chunks of software in it. I have no interest in trying.

Because they use Typescript.

>The stop-the-world garbage collection is a big pain for games

There is a number of languages that allow manual memory management: Zig, Nim, Rust and few others

reply
archargelod
1 month ago
[-]
> There is a number of languages that allow manual memory management: ... Nim

Nim not only has support for manual memory management, but there're several gc modes that are not stop-the-world.

Also, since Nim 2, the stdlib now is using ARC by default, which is deterministic and has advantages over conventional garbage collection.

reply
andai
1 month ago
[-]
(2016)
reply
naranyala
1 month ago
[-]
reply
alexmyczko
1 month ago
[-]
reply
ethin
1 month ago
[-]
I write all of my games in pure C++. C++ all the way. FMOD for the audio engine, Steam Audio or Atmoky TrueSpatial for HRTF/geometric occlusion, and Jolt Physics for, well, physics. I'm sure many might say I'm a bit insane to do that, but eh, I do it anyway because it's fun.
reply
throwaway2037
1 month ago
[-]
Before I even read the blog post, my first thought was: "Bullshit, this feels like clickbait. Simple DirectMedia Layer (SDL2) [one of the most popular gamedev libs for indy games] is written in pure C." I guess that the only backdoor to this clickbait argument in 2026 can be: "My graphics/audio libary is written in pure C, but I use bindings with language X (C++/Rust/Zig/etc)."
reply
zuluonezero
1 month ago
[-]
Nice looking games though.
reply
nottorp
1 month ago
[-]
Btw, in the wannabe indie gaming scene it doesn't matter what language or tool or framework you use. It matters if you finish the fucking thing.
reply
globalnode
1 month ago
[-]
this is refreshing. personally i do all my hobby stuff in C or Python. I could certainly use c++ if i wanted to but templates and cin/cout were such monumental jokes how can i trust the rest of the language? i too have contemplated writing my own language but to paraphrase the author, id rather make games than languages and C/Python are good enough.
reply
Western0
1 month ago
[-]
why?

because You know C

reply