The mythical C and C++ replacements
I watched this recent talk (note this post is from 2018) by Bryan Cantrill (Summer of Rust), and thinking about it got me to write up some older periodic thoughts. It's probably worth reanalyzing this topic every few years (especially if I look deeper into any of the languages listed below) but consider this the first one.Unlike Bryan I'm more interested in the theoretical replacement language for game programming rather than systems programming. The big "enemy" here is C++, but C is still very common especially at the library and middleware layers, so I think we're in alignment in generally aiming at C and C++ together.
(Quick links to options considered below: Nim, Rust, Future C++, D, Objective C, Lua, Non-combatants, Java, Urbit, Pony, Zig, Crystal, Red, Common Lisp, Some Scheme, Odin, Clowns. Note that for now some updates are contained in their own sections at the end, rather than in the language sections themselves...)
I still like C, but I think one thing it shares with C++ is that either option is fairly irresponsible to make something brand new in it if there are important security threats that your program must deal with. With discipline and tooling know-how you can responsibly use either language, or at least more responsibly use them, but it still may not be a good idea when there are other options that give you safety against certain classes of security issues without any discipline required.
Systems programming is rather vague and includes things like relatively slow Perl/Python programs (not just scripts), but one interpretation of it includes hard problem solving at a layer close to the physical computation (where things like the CPU's manual come in handy) and where the problem domain matches up well with solutions near that layer. C has traditionally done well here. Similarly game programming can include a little TI Basic Calculator game or some arcade-style experiences written in a high level and relatively slow language like Python. But the kind of game programming I'm talking about was described by Brandon Bloom: "You have to solve every hard problem in computer science, 60 times a second." C++ dominates usage here, even if it's not the only option that can calculate that fast. (The whole calculation envelope is 16ms, that's a lot of headroom.)
Immediately this deterministic 60hz rule (with several important tasks needing to be able to finish even faster than that to fit in the envelope) rules out garbage collected languages. (Edit: modern me disagrees.) Cantrill also doesn't like GC so much for some systems programming since sometimes you just need full control of the runtime behavior and the GC can get in the way.
Or is GC ruled out? I'll start with my personal favorite contender in this space (at time of post written, not as of 2020s+) before I go into my thoughts (limited as they are) on other languages I either like or have been vaguely aware of.
This post of mine is very ignorant, if any fans of languages listed below wish to correct me in the comments, or just gush over one of the languages and how it has certain features you love that make you want to use it over ever using C/C++ again, please go ahead. Also if there's a language I'm not aware of that you think has a chance to unseat the champs in the domains of systems and game programming I'd be interested in looking at it a bit.
Nim
I've been following Nim since it was called Nimrod. Needless to say, I like it quite a bit.
It has a garbage collector. But the garbage collector is quite flexible. For one, you can actually swap out the GC to different implementations choosing from a reference counted "GC", to a mark-and-sweep style, to a soft-realtime style, and you can temporarily disable it too. This means that if you're writing a game and you cannot tolerate non-deterministic GC pauses of unknown length that lead to dropped frames, you have escape hatches.
Nim has an additional escape hatch in that it exposes a malloc/free combo for you to use directly. The GC won't touch that memory. If all your memory is done that way, there's nothing for the GC to do, and no overhead. But it's there if you need it.
Nim compiles to C (and others) so naturally it interfaces with C code very well, this is an important criteria for any language looking to displace the C and C++ hold.
Rust
Rust has no GC. But it used to have one, and you could use it with an '@' sigil. They decided to remove it, however, which made me sad. Cantrill points out that this is kind of a good thing, that the designers are willing to throw away work and rip things out of the language (his example was green threads). I kind of agree, but of course when you deal with groups like that it's only a matter of time before they rip out something you like. From Cantrill's talk in describing the Either monad/generic type that is used for functional error handling, it sounds like Rust has some nice support for that (is it any different than Java's Optional support? I haven't looked into it). But what if they read Kent Pitman's papers (e.g. this one) on error handling and changed it to a conditions-and-restarts type of language? Their people are also very good at propaganda. It's important to look at the people behind the languages (and the community in general) since they're going to make the changes you have to live with if you adopt it long term.
Still, Rust seems like a worthy contender. I think I would rather take a job in Rust than a job in C++. However, its only safety guarantees are memory safety, and if you can use a language that gives enough GC escape hatches, you can just use a GC language and never have a brain-wracking fight with the borrow checker.
C++20xx
I know C++98, I don't know modern C++17 (or really much of anything in C++0x and later apart from a couple Boost libraries that implemented it while we waited for the standards committee). They seem to have all the pointer types now though to support much of what Rust offers, even if it's in a clumsier and still fundamentally unsafe way. It's possible that a future version of C++ will come about that addresses all the sins of C++ and that programmers won't have to know C++98 anymore, but I doubt it.
D
It had its chance. I haven't played with it and don't remember many details, but it feels like pre-Rust and that Rust is the modern attempt at a language-after-C++ that we should rally around if we had to choose sides.
Objective C
This seems to have remained an Apple-world only thing. Similarly C# has remained an MS-world only thing. Other than that it's similar to D, but has a large community in the Appleverse. But even that will go away as Swift gains features and adoption.
Lua
Lua will continue to be the game programmer's go-to embedded scripting for non-time-critical (doesn't need to complete once per frame) things like game AI. But a whole engine in it? I don't see it. It's much like Node. Fast, but has too much nondeterminism and lack of access to the metal.
Java, C#, Go, OCaml, Haskell, Erlang/Elixir, GDScript
I'm lumping all these together as non-combatants. Largely because of their GCs but there are other reasons for each individually. Java took lots of marketshare from C++ for basically everything C++ was being used for except those low level systems and game programming and embedded systems applications (though Java has tried to make inroads there, arguably even originally purpose-made for embedded systems, and maybe you'd call Android a success on the embedded systems front). Any language similar to these isn't going to compete. These languages mostly take market share from each other, some from Java, some from higher level languages like Python/Perl/Ruby.
Minor 2024 update but I thought to clarify C# and realized I should add GDScript to this section as part of the same clarification. As far as I know Unity eventually switched to using the real C# people use everywhere else, so for game code in that engine, C# seems to be fine. And Godot has its GDScript. Also as far as I know Microsoft keeps rewriting more things from C++ to C# (though I hear some Rust has been introduced as well). I think I should give C# more credence. But in the context of games, at least, it and GDScript are non-combatants because a C and C++ replacement has to in principle be able to replace C and C++ in all domains, not just one. No one's going to ever use GDScript to write an OS in.
Another minor update from 2024, but in 2022 I started to wonder a bit again about OCaml, because it's being used in high frequency trading applications. Let me repeat a comment I made on hacker news at the time:
There are also prefetch instructions. I listened to https://www.youtube.com/watch?v=SetLtBH43_U recently (transcript: https://signalsandthreads.com/memory-management/), part of it talked about some work in OCaml's GC.
> ...each individual memory request that’s not in cache still has to wait the full 300 cycles. But if we can get 10 of them going at the same time, then we can be hitting a new cache line every 30 cycles. I mean, that’s not as good as getting one every 16 cycles, but it’s close. You’re actually able to get to a reasonable fraction of the raw memory bandwidth of the machine while just traversing randomly over this huge one gigabyte heap
https://github.com/ocaml/ocaml/pull/10195 shows the change adding prefetching to the marking phase (https://github.com/ocaml/ocaml/pull/9934 was done earlier for sweeping). There are some benchmarks in the thread/linked from the thread.
Java post ZGC
Effectively pauseless GC exists for the masses now. Java is back in. Its lack of a native unsigned int type is annoying.
Nock, Hoon, Urbit ecosystem
This might fit the bill -- except it requires buying into replacing everything, not just the language. Perhaps a very long term solution. Though last I checked Nock was still implemented in C...
Pony
I agree with their "get stuff done" philosophy, I think they rank their values in the appropriate order. However, there was that 1/0 drama recently. I think Pony will remain obscure but some of its ideas may filter out.
It has a GC, but it runs at more deterministic times. I don't know how configurable it is.
Zig
A bit like Pony, but with less marketing, this seems like a toy language that will remain in obscurity. Perhaps some useful ideas are there, I haven't taken a serious look at it so just like Pony and the next couple languages it's one of those "look into this if we must do this in a no-GC language" things to keep in the back of my mind should I find myself working on something that calls for it.
Memory is manually managed, so there's no GC to worry about. I read somewhere that Rust is taking a feature from it (or at least implementing a similar feature, not sure if they were inspired at all by Zig) for custom explicit allocators though (as I understand from the talk above stable Rust at this time doesn't let you allocate outside of Unsafe).
Crystal
Another Pony-like (in my view) but with Ruby inspired syntax, I think it has a GC (not sure of its tunability) but it also has low level alloc/free.
As of 2024, it seems like it's declined.
Red
Also similar to Pony, I think I would like to learn this one first though. It also has a GC. I don't know how tuneable it is. However it has a DSL called Red/System that is quite exciting, for instance you can talk to the CPU's FPU directly without having to write assembly code! So there's interesting very low level potential here, while also providing very high level abstractions. This is probably my favorite choice next to Nim.
Common Lisp
Like Red, but perhaps not as elegant (without a custom macro library anyway). I have this on here mostly because I'd like to use Lisp for everything, and it's actually capable here because Lisp supports both the very high and the very low. It's garbage collected, and none of the mainstream implementations that I know of have highly tunable GCs that could completely eliminate non-determinism... But there are some hatches, you can probably convince yourself about certain GC behaviors even if you can't guarantee them (e.g. by disabling the GC at critical times). You can manually allocate on the system level, you can use mmap, and take off pressure on the GC.
There's a modern existence proof with the Lisp game Kandria being released in 2023.
Lisp has the additional benefit of being used historically in very low level applications (games, OSes, space craft) and very high level applications (CAD, web stuff). The existence proofs have been done, which is more than one might be able to say about some of the above contenders. The final escape hatch is having your programs being written in a modified Lisp that Common Lisp itself translates to your lower level code (i.e. what was done with Crash Bandicoot and GOAL). Since Lisp makes code generation so easy, it may well be very worth it to use Lisp even if your target source code that gets passed to another compiler isn't Lisp. Given the craze JS programmers have for Babel, this shouldn't be seen as that weird...
As of 2024, I kind of think everything should be written in Common Lisp. It won't be easy, though, so I understand why people who even like Lisp a lot (me included) would make a different choice. Still, even with the not state of the art GCs, I don't think the language precludes it replacing a lot of remaining C and C++ code.
Some Scheme
Maybe Chicken Scheme or Racket provide better solutions than the current CL ecosystem, so they're worth a look too. I'm very intrigued by one of Bryan's offhand remarks about a Chicken Scheme faction at Joyent...
Summary
Prediction wise, I think Rust is well-positioned to take down the last remnants of new C and C++ code and will continue to chip away at usage share. However I would prefer that Nim, Red, or Common Lisp did so instead. Of those three, Nim seems like the easiest to work with and has a lot that I like going for it, but I worry it will just capture some of the Go/Java/Python crowd. Nim could use a sugar daddy corporation / foundation. Red might be as nice as Nim, I haven't played with it yet. Common Lisp is Lisp, moving the open paren a symbol to the left causes people to lose their minds and shout total nonsense.
Minor update 2021-5-16
Just casually thinking about this again, thought I'd add a few new sentences with where I'm at now. Rust has seen accelerated growth, though received a harsh blow with Mozilla dissolving a big group -- however that might prove to its longer term advantage as those former employees disperse and push for Rust adoption internally at a variety of other places. I'm happy to see it displace C and C++, not happy to see it displace other things, and hope I never have to program in it or interact much with its community.
I'm less hot on Nim, however I'd still rather use it than anything except CL -- with one possible other exception. It's also seen growth, but a lot more muted.
Zig has seen more rapid growth, but I'm still fairly ignorant about it. Some high profile people have expressed some favorable opinions. (I decided in 2022 though that their "VP of community" is kind of a goober.)
Anyway, the new exception, funnily enough, is Java. I think the recent work on its ultra low latency GCs (multiple ones, in OpenJDK, not just Azul's!) put it back in the running, and it may have the final laugh, the ultimate Java revenge to more completely oust C and C++.
C++ isn't slouching either, but I hope to not have to program in it, and am sad when it's used instead of anything else. Though at this point I think I'd rather use it than ANSI C 89 (or even gnu89). ANSI C is beautiful, in a similar way that Scheme is beautiful. Neither are what I want to be my workhorses.
I still wish CL the world. It (and some Lisp-inspired offshoots) continues to see growth, there are even regular Lisp game jams, a CL game got on Steam... I won't be optimistic but I at least don't plan on working in anything else.
Minor update 2022-02-19
Odin
Now on my radar, though I'm not optimistic for this language either. It's rather dull and unimaginative, "yet another ALGOL", at one level. It's entirely manually memory managed. But it has some neat ideas around custom contextual allocators and syntax for SOA/AOS, and is doing the right thing in terms of potentially increasing adoption in the needed domains by being used for a kickass middleware tool that can be used by game or animation studios. Having actual commercial products in the relevant C/C++ domains making use of the language you hope will replace them is crucial. Odin continues to be used for cool stuff.
Minor update 2024-09-12
Clown Options
Just wanted to put out there that I've long been aware of Jai and V as clown options. I will not elaborate further.
It doesn't matter?
A comment by pron over at hacker news earlier this year kind of released me a bit from caring as much about all the "energy" of most of the languages on this page that I sort of deem inferior to my favorite language, especially when so much of their activity seems to not be relegated to domains where C and C++ rule but in trying to take on domains where e.g. Java has been just fine for decades. pron has a lot more patience than I do about arguing with fools over their misconceptions about garbage collection (and he's actually an expert, working on OpenJDK), his comments are usually informative to browse through occasionally even if there are disagreements, but here let me just quote this comment in its entirety:
Given that the no-GC-by-default market is ~10% of the global software market [1] with no signs of shift in either direction over the past couple of decades, which sounds about right to me (considering the percentage of programs that need to run in memory-constrained environment or must have precise control over memory), it seems that the number of those who may benefit significantly from a different choice is small and so it doesn't look like anyone wants or needs to be convinced of anything. "GC languages" already command ~90% of the market and have little to gain from such a small market of potential converts, and the others aren't trying or succeeding in increasing their market share, so who cares given the small stakes?
[1]: https://www.devjobsscanner.com/blog/top-8-most-demanded-programming-languages/
So the C and C++ market along with others that we could put in the "manual memory" space are like 10% of the market. Do they really need to be crushed to 0? Are they realistically ever going to get back to even, say, 20%? A sane answer to both questions is no.
Of course, if you're a programmer interested in the domains where manually memory managed languages still dominate (though I wonder, if you count things like Godot with GDScript as non-C++ even if the engine itself is C++, and if you include indie games, how much longer will C++ have a big market share in even games?), things are different, and you might still want to care a bit. But consider how much you care about that domain vs software as a whole. And even in the manual memory space, there's still hope to do better than C and C++ (even the white house issuing a press release summing up to say stop using C and C++ was hilarious), even if I believe just accepting GC (and working around performance challenges) would be better.
Posted on 2018-08-14 by Jach
Tags: programming
Permalink: https://www.thejach.com/view/id/354
Trackback URL: https://www.thejach.com/view/2018/8/the_mythical_c_and_c_replacements
Recent Posts
2025-03-15
2025-03-03
2025-02-13
2025-01-14
2025-01-10