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.
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.
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?
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.
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).
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.
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.
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.
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).
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.
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.
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.
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.On top of likely having worse performance.
Have you bothered to look how GCC and clang are implemented?
Drivers, and extension points for userspace.
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.
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.
Oh, and smart pointers too.
And hash maps.
Vectors too while we're at it.
I think that's it.
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.
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.
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.
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.
Even with the recent extension where it looks like it isn't, the compiler adds one for you.
Regrettably not every C++ feature is free if you don't use it. But there aren't many that aren't.
That's definitely harder.
Mindread much?
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.
In the gamedev space, I'd say too few of them do.
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.
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?
>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.
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...
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.
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.
So? Their interface is via C, just like OpenGL was.
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.
Say more with less.
linux attracted 2,134 developers in 2025
that kinda weakens your argument a little bit
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.
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.
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.
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...
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.
But I find string management in C awful and would like to borrow it from C++. Only the string management
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++.
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.
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.
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.
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.
Not being facetious, but couldn't you say that about almost any language? What makes you say it about Java?
It's an ongoing struggle!
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.
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.
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.
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.
Try Clay!
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.
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.
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.
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...
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.
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.
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.
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...
What languages compile fastest?
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/
It does make me wonder why Pascal never became more popular. Fast compiling is a big advantage.
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
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.
because You know C