Blog 4 min read

John Carmack: A C++ Programming Legend

Share this article
John Carmack: A C++ Programming Legend

Have you ever watched a basketball or soccer player play such a simple yet effective game that you wonder: why can’t everyone play like that? He seems to use only simple techniques.

As a C++ programmer, I had the same thought when exploring John Carmack’s source code: the code is so simple that we wonder why we can’t write software like he does.

Let’s explore some design choices in the Doom 3 source code and try to understand why the code, even though it’s simple, is very efficient.

On November 23, 2011, id Software kept up the tradition and released the source code of their previous engine. This source code was reviewed by many developers; here’s an example of Doom 3 feedback from Fabien Sanglard (original source):

Doom 3 BFG is written in C++, a language so vast that it can be used to generate great code but also abominations that will make your eyes bleed. Fortunately, id Software settled for a C++ subset close to “C with Classes” which flows down the brain with little resistance:
  • No exceptions.
  • No References (use pointers).
  • Minimal usage of templates.
  • Const everywhere.
  • Classes.
  • Polymorphism.
  • Inheritance.

To sum up, only a subset of the C++98 standard is used. And here are some design choices of Doom 3:

1. Provide a common base class with useful services.

Many classes inherit from the idClass:

doom10

The idClass  provides the following services:

  1. Instance creation.
  2. Type info management.
  3. Event management.
doom11

2. Make string manipulation easy

Generally, strings are among the most widely used types in a project; many operations are performed with strings, and we need functions to manipulate them.

Doom 3 defines the idStr class, which contains almost all the useful methods to manipulate strings — no need to define your own methods, as is the case with many string classes provided by other frameworks.

3. The source code is highly decoupled from the GUI framework (MFC)

In many projects using MFC, the code is highly coupled with its types, and you can find MFC types everywhere in the code.

In Doom 3, the code is highly decoupled from MFC; only GUI classes have a direct dependency on it, as shown by the following CQLinq query:

doom3

This choice has a big impact on productivity: indeed, only the GUI developers need to deal with the MFC framework, and the other developers don’t have to waste time with MFC.

4. It provides a very good utility library (idlib)

In almost all projects, the most used types are utility classes, as shown by the result of the following query:

doom4

As we can see, the most used ones are utility classes. If C++ developers don’t use a good utility framework, they can end up spending much of their development time dealing with the technical layer.

idlib provides useful classes with all the methods needed to handle strings, containers, and memory, which makes the developers’ work easier and lets them focus more on the game logic.

5. The implementation is very easy to understand

Doom 3 implements a hardcoded compiler, and as C++ developers know, developing parsers and compilers is not an easy task. However, the implementation of Doom 3 is very easy to understand, and its code is very clean.

Here’s the dependency graph of the classes used by the compiler:

doom16

And here’s a code snippet from the compiler source code:

doom15

We have already studied the source code of many parsers and compilers, but this is the first time we’ve encountered a compiler whose source code is so easy to understand — and it’s the same for the whole Doom 3 source code. It’s magic. When exploring the Doom 3 source code, we can’t help but say: WOW, it’s beautiful!

To sum up, the Doom 3 source code is very clean, easy to understand and maintain, and it uses only a subset of the standard. No advanced techniques are used, and it follows basic best practices for code design, naming, and formatting.

We can say that John Carmack’s secret was the KISS principle, as defined in Wikipedia:

KISS is an acronym for "Keep it simple, stupid" as a design principle noted by the U.S. Navy in 1960.[1][2] The KISS principle states that most systems work best if they are kept simple rather than made complicated; therefore simplicity should be a key goal in design and unnecessary complexity should be avoided. The phrase has been associated with aircraft engineer Kelly Johnson (1910–1990).[3] The term "KISS principle" was in popular use by 1970.[4] Variations on the phrase include: "Keep it simple, silly", "keep it short and simple", "keep it simple and straightforward",[5] "keep it small and simple" and "keep it stupid, simple".[6]

What's interesting about this definition is the following assertion:

The KISS principle states that most systems work best if they are kept simple rather than made complicated.What lessons should we learn when adopting the new C++ standards?

The new standards introduced many interesting new features. Assuming that using all these features will automatically make your code more efficient is a bad idea; many new features are more useful for developing generic libraries, especially all the features related to generic programming.

Don’t force yourself to use all the new features; use a feature only when it’s genuinely needed and helps make your code better or more efficient. For example, this interesting post talks about the drawbacks of overusing the auto keyword.

Share this article