Here's an example I did: https://gist.github.com/JamesDunne/a94782bc39d95515f7dcc8516...
Also, I would generally move all implementation code out of header .h files into standard .c files. Header files are traditionally just meant to contain forward-declarations of types and methods.
We use the 'happy path' style at work. It is OK. I find it has its own set of disadvantages as well. I am also not a fan of negative/negating conditions.
Whenever possible, I try to write the code the way I would explain it in plain language. This may be antithetical to the majority of modern programming, but I am OK with that.
tbh, i have seen nested ifs used in video game programming a lot. and i came to the conclusion that it has to do with the else clause that the return early method doesn't provide. the else clause is always doing something because games are never supposed to fail...
I'd also add that it's a good idea to break out complex condition checks to their own independent if statements on separate lines. I'd even go further and decompose the condition expression into individual boolean variables so that if you build in debug mode you have all the evaluated values held in variables for inspection. In release mode the variables should be compiled away.
There are some practical and aesthetic benefits that come from reducing nesting and breaking apart complex if conditions:
* less horizontal scrolling in your editor * no need to parse complex boolean expressions all stuffed into very few `if` statements * easier ability to step through code within a debugger and follow the execution logic more exactly * more distinct line numbers for crash dumps / stack traces to refer to in order to exactly identify which condition or evaluation is causing a failure
That last point is very beneficial when you hand your code off to someone else and they send you back a stack trace to investigate. Your code probably crashed at a complicated line of code full of boolean-combined expressions and any one of them could be at fault. All you know for sure is that something went wrong at that line number. No other hints given as to what went wrong or what the value of all the relevant variables on that line are.
I also wanted to comment on needing it because games aren’t supposed to fail. The way you actually do that is not to try to recover from errors but to surface them quickly and fix them at the point of failure. Ideally before shipping. Recovery is usually very difficult because games are a collection of very dependent state and if you don’t recover correctly letting the game continue after an error is very likely to result in all sorts of other bizarre issues happening. This can also be very subtle where the accumulation of errors leads to a sudden obvious issue and finding the root cause is very difficult. Whereas failing early and loudly makes things much easier.
A minor one, but still saves some time: You don't have to think about build system. Just compile a single .c file on the command line. You can quickly add and remove .h files while prototyping, without having to add/remove files to the project.
A major one: is that you cannot create cyclic dependencies. This helps to get your call hierarchy right. When using header files only, the only way to get cyclic dependency is to use a forward declaration and every time you feel like you need to do that, a big red flag is raised in your mind. And then you start to think how to do it properly. This is even more important in C++ where you have to think about responsibilities of every class. It prevents you from creating too coupled code.
When the project grows and compilation times get long, you should split all of those into separate compilation units, so that you can use multi-threaded builds (via ninja, or make -j).
The headers are library code, and having more files just means more maintenance and build complexity. Is there another advantage I am not aware of?
#if defined(__WIN32__) || defined(__WINRT__) || defined(_WIN64)
fopen_s(&file_to_read, path, "rb");
#else
file_to_read = fopen(path, "rb");
#endif