TheJach.com

Jach's personal blog

(Largely containing a mind-dump to myselves: past, present, and future)
Current favorite quote: "Supposedly smart people are weirdly ignorant of Bayes' Rule." William B Vogt, 2010

The mythical C and C++ replacements

I watched this recent talk by Bryan Cantrill, 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.

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. 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 before I go into my thoughts (limited as they are) on other languages I either like or have been vaguely aware of.

This post 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



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

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.

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.

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

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.


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

Back to the top

Back to the first comment

Comment using the form below

(Only if you want to be notified of further responses, never displayed.)

Your Comment:

LaTeX allowed in comments, use $$\$\$...\$\$$$ to wrap inline and $$[math]...[/math]$$ to wrap blocks.