Last time we explored some commonly found alternatives to using enums for error codes such as asserts, contracts and std::expected. Finally today we consider some unthinkable options.
The code examples given in part 1 and part 2 strongly focused on simple (and I’d argue, quite common) form of error handling: run a sequence of operations, and if any of them fails bail out and report an error. We tried a few alternatives but they all came with caveats. Error code returns polluted a lot of the logic with if ( error ) { return error; }, std::expected was a bit more concise but demanded we rewrite the signature of the functions we call to fit the monadic form and finally contracts allowed for cleaner user code but aren’t really made to do custom error handling (if they make it into C++26 at all) or recoverable errors (like a missing file).
I wanted my program to boot up faster so I tried to multithread it with both executors and the more classic TBB.
Back in 2020 I did a remote talk at CppCon about my work on making Stellaris boot up much faster. I later brought similar improvements to Hearts of Iron IV and Europa Universalis IV (although I’m afraid the latter was never pushed to the live branch, you have to opt-in to a beta version). They key to those improvement was, of course, concurrency: put stuff to load in the background if it’s not needed upfront, and use multiple threads to do the work when possible.
In our previous article we talked about the limits of using enum class for API error reporting. Today we look at alternatives.
Last week, we showcased how C++11’s enum class can be used for error codes and discussed what is, in my opinion, its biggest limitation: the inability to easily use them in boolean contexts to see if an error did occur. While it was possible to add the functionality, it required some amount of code to write and didn’t generate amazing assembly compared to native types unless we turned aggressive optimizations on.
C++11 gave us enum class and while it’s great to have scoped enums I don’t find it great for error handling. Let’s talk about why.
Most of my readers, I hope, have been able to use C++11 for a while now (if not hello, I’m sorry the world has changed to become this weird during your 14 years sleep). With it came a small change that allowed for better scoping of names without resorting to weird quirks: enum class. The idea is simple: owing to C, enum values in C++ belong to the class or namespace they are declared in but if we add the class keyword to the declaration they know become their own scope instead of leaking to their parent.
Let’s talk about game simulations. In this episode we look at different ways to approach task-based parallelism.
During summer we explored some simple multi-threading models. They had the advantage of giving us a migration path for existing code that runs a very serial/imperative simulation. Now is the time to explore what other approaches we could take for a new project, or if we’re willing to refactor a lot of existing logic. Today we look at task-based parallelism.