Les Imbroglios d'Alexis Breust

De l'impro sans bugs et du code lâcher-prise.

Game Programmers and the C++ collapse

Everyone with little experience will tell you: if you want to program your own game engine, C++ will allow you to get the performances you need. Indeed, C is missing high-level quality-of-life features, and there are no other practical choices.

Well, that state of mind is changing among game developers.

Let's focus on why C++ is slowly digging his own grave.

C++ is dominant in the game industry

All the big game engines you might have heard of (Unity, Unreal Engine, CryEngine, Godot, Lumberyard) are written in C++. And Unreal Engine also provides C++ as a scripting language. And it is that way mainly because of performances.

As you can see, game developers are amazing with C++, they give you open worlds loading
thousands of assets dynamically and controlling incredibly complex AI or physics systems.
Source: Horizon Zero Dawn (Decima Engine) - © Guerrilla Games

60 frames per second means you have to update all the logic of your world in 16ms, so it is a fact that game developers will look for performances above all.

Yeah, great, but why not use C? Or Rust? Or Go? Or whatever?

There's surely some technical debt due to all the well-known engines programmed in C++ and you don't want to re-program everything in a recent language if you're not sure of the gain. But that's not all…

Why C is not preferred?

I think there are valid reasons people tend to use C++ over C:

  • overloading and templates can improve the quality-of-life for the programmer ;
  • classes and inheritance can easily fit some design patterns ;
  • language is maintained and evolving regularly (C++11 gives auto and ranged-for).

So, between C and C++, the latter clearly gives more to the programmer, even if he won't use all the language's features.

Why not another language?

First of all, Go uses a garbage collector, which is a no-go since it means you won't be able to control the memory precisely, not knowing when some deallocation will take place.

Rust's garbage collector is not mandatory, which is nice. Moreover, it's designed to be a runtime performant. It is definitely a language to follow, as it is trying to get some games made with it.

Rust is fine, but it lacks something important: it is not designed for game development. So did C++, you might say, but I will detail more on that on the last section about Jai.

Why would you need another language if C++ is all right?

Well… I never said C++ was all right…

C++ doesn't help game developers

Like Rust, C++ is not quality-of-life-oriented, and there are many problems that made it slowly become a pain in the neck. The main one is obvious to anyone who tried to work on medium-to-large projects in C++: SLOOOOW COMPILATION TIMES.

C++ is too slow to compile

Nicolas Fleury, a technical architect at Ubisoft Montreal, gave a talk during cppcon 2014 intitled C++ in Huge AAA Games.

He notably sums up their build system for game like Assassin's Creed Unity in order to speed up compilation times:

  • Blob (called unity build): concatenate all your .cpp files into a big file so that the compiler has only one thing to chew on (this involves a very consciencious coding style) ;
  • Multiple blobs: so that you don't recompile the physics engine when working on rendering ;
  • Dynamic splitting of WIP blob: separate the files you work on into its own compilation unit so that you don't recompile the full blob either ;
  • FASTBuild: an open-source build system that dispatch compilation to available machines on the network ;
  • Includes remover: a tool to remove useless #include, so that the compiler does less IO and parsing.

And you know what? He gladly says that with all this, they can achieve a total recompilation of Rainbow Six: Siege (8 millions C++ LOC) in 3 minutes. That's extremely slow! Don't get me wrong, Nicolas Fleury and his team did an amazing job getting there, but, as you can see, C++ is just slow to compile. Computers are way faster than that!

And I don't want to elaborate on how much it's a stupid amount of work to set up such a build system. Remember, that's a private company, they can afford doing that, but any open-source project won't be able to propose such a thing. Chromium (estimated to 7 millions LOC) takes 3 hours to do a full build. Sure, 3 minutes feels nice now.

A rare view of a C++ compiler during a Chromium compilation process.

C++ requires you to be insanely careful about what features you use

Specific to the performances needed in the game industry, Mr Fleury also details coding decisions that are needed for fast runtime execution (and the compile time they get):

  • No RTTI: you prefer to control the memory details yourself ;
  • No exceptions: they are simply slow because of the constraints of unwindable stack at any time ;
  • No STL containers: std::vector is slow, and complex template code takes time to compile ;
  • No boost: surely the library is impressive, but it's never a good idea to use it in serious applications ;
  • Very small subset of templates: use it at mininum as it increases significantly compile times.

In definitive, game studios tend to use a "minimal C++", sometimes called C+. And all annoucements about the evolution of the C++ language (since C++11) has been regarded as useless. Indeed, as it often concerns templates of new STL features, the base language does not improve at all.

C++ requires you to be insanely careful about what features you use

C++ committee decisions are disconnected from these problems.

What can they do much about it? I don't really know, at this point, but they might not be on the right train of thoughts.

Fact is Modern C++ is just growing up so much it will soon collapse under its own mess.

That fealing is shared by more and more senior developers and is the starting point of saying: "ok, we have to do something here", and that's how Jai was born.

Jai, a better C

I've been waiting for the Jai Programming Language to be out for some years now. Fact is I followed Jonathan Blow since his very first video about it, and I still watch him during his recent livestreams. You know him, it's that game designer and developer who made Braid and the The Witness.

The main reason he fealt the need for a new language was merely due to the current status of the game industry. People use minimal features of C++ in real-time softwares, and Jai wants to propose a language designed around what sensitive applications really use.

The main focus is the good developer's quality of life:

  • compilation:
    • no object files: concept is that your project is recompiled fully each time ;
    • speed: a whole game of 100'000 LOC is compiled in less than 1s (in January 2019) ;
    • speed target on release: one million LOC per second ;
    • error messages: clear and expressive ;
    • integrated build system: your project is described in Jai ;
    • no header file: no order of declaration within global scope ;
    • meta-features: to #modify your code dynamically at compile-time, all that is still written in Jai ;
  • runtime:
    • runtime type introspection: to prevent the need of a meta-language describing your structures ;
    • no garbage-collector, easy allocators: memory tools within language specifications.

Work in progress of a sokoban game written in Jai.
Source: Twitch stream - © Thekla January 2019

With the previous list, I summed up all I could think about the language without going over much syntaxic details as these can still change.

Waiting for release

The main problem with Jai, though, is that it's been some time, there's multiple developers working on it, but it is still not released.

Thanksfully gingerBill started thinking the same and decided to write its own compiler. He went for his own language called Odin, but it is very similar to Jai current syntax and definitely shares the very same ideas Mr Blow insisted on.

There are differences with Jai, for sure, as these are not the same languages. Here's the main ones:

  • module system: taken from Go ideas, a folder is a package, which provides a namespace ;
  • foreign API: to interface with C libraries.

If you are interested in this project, check Odin's Github repository.