Minimum Educational C++
Minimum Educational C++
I have spent the last few months pouring over most of the C++ style guides I could find to figure out what are the most common recommendations. I'm mostly trying to figure out what's the minimum necessary for someone to study to learn modern C++, but also to sort out what's commonly thought of as "modern C++."
About Indoctrination
One of the things I always strive for is anti-indoctrination. I find other courses try too hard to turn students into true believers of the language. The course author will blather on for thousands of words about how amazing Python is; show off "terrible" C++ code that they cherry picked; rant breathlessly about all the amazing things you can do (very slowly) in Python; and all to make the student believe that Python is the greatest language ever.
The problem is, Python is not the greatest language ever, so the authors of these "Rah Rah Python" indoctrination courses are robbing students of their ability to work with the language long term. Every language has warts, and eventually students will run into those warts, but if the student thinks the language is perfect they'll feel stupid rather than learn to avoid the wart.
A very good example of this is the mantra that Python's indentation syntax is "easy." Indentation syntax is only easy if you came from a language that had bounding characters to denote structure. For those of us coming from Java the Python indentation is a breath of fresh air because our brains are already trained to know the structure by its indentation. For a total beginner this is very difficult to see and you'll see them frequently make these mistakes:
def somefunc():
print("something")
def theother():
print("hello there")
I never see this mistake in JavaScript or C students, but see it in Python students all the time. Just imagine this is also hundreds of lines of code they've been working on but suddenly "it doesn't output 'hello there'" anymore. All it takes to make this mistake in hit ENTER at the wrong time and not notice a few spaces. Pretty easy to do even for professionals.
In this simple example the indoctrinated student will feel stupid because they'll believe "Python is so easy." If it's easy they must be an idiot. Students who are told the truth--that Python's indentation is really only good if you're experienced--won't feel so bad because their understanding of the language is grounded in reality.
The other reason I'm against indoctrination is it turns people into idiots who blindly believe anyone in charge. When you're told over and over that Python is the greatest language ever you'll very easily slip into believing that the maintainers of Python are infallible. This is why so many people literally believed idiots who claimed that "python is an interpreted language" when there's literally a disassembly library for the Python bytecode. Indoctrination is so powerful that people in the Python world believed that two piece of Python code were wildly different even though they produced nearly the exact same Python VM bytecodes.
Why did they believe this? Because those infallible Python maintainers told them this was true, and all those indoctrinated true believers never though to...just dis()
the code to see if it was actually true.
Incidentally, in my latest Python course I teach people how to use
dis()
to study Python so they'll never be tricked again...and because it's an awesome way to see how a computer works.
C++ Without Indoctrination
I'm saying all of this because I just know there's people in the C++ world who also think that the only way to use C++ is to follow exactly what Bjarne Stoustrup wrote in his terrible C++ books. I know who these people are because they're bristling right now at me saying his books are bad--not because they've actually read them--but because I'm criticizing Bjarne and being indoctrinated programmers this translates into criticizing them. If you read his books though, they are really bad. I have a whole other post about everything I found, but I'll just say that he claims the book is for total beginners and then dives into insane C++ tech that's not even supported by most compilers yet.
If not even the Clang devs can get it right, then how could someone with zero programming experience learn these complicated features? I rest my case.
I believe the trick to teaching C++ without indoctrination is to lean heavily on the advice of companies and organizations that are more successful and authoritative than any of the C++ true believers. That's the point of this essay. To find that subset of C++ that's actually recommended in industry, strip it down a little bit further, and catalog the rest so someone can study more if they want. Then, when the C++ true believer comes saying that my course is junk because I don't teach the latest range based for-loops I can point them at Google's C++ standards. Or better yet, just point out that even the C++ committee admits they are broken.
The Style Guides
With that in mind, I spent the last few months reviewing many different guides, but three came out on top as the most practical and/or commonly referenced:
After reviewing all of those I came to the conclusion that all of them are really weird. Let's take the Epic Games Guide:
- Really bizarre CamelCase for everything. I don't think I've ever, in 30+ years of C++ coding, thought CamelCase everything was normal. This definitely smacks of some head honcho at Epic just being a weirdo and forcing everyone else to do it too.
- Lots of weird macros to set things up like
UCLASS()
rather than templates, which is kind of what templates are for. I'm guessing Unreal predates templates? I don't know? Templates are ancient and when combined with inline functions and enums virtually eliminate the need for macros. #pragma once
in all headers and use forward declarations. Not necessarily bad, but that's different from others. My guess is they struggle with build times (and I'm sure never thought the problem may be their weirdo macros).- Single letter prefixes instead of namespaces? Really? It's not Objective-C.
Otherwise, not that bad in terms of recommendations. Google's though has many similar things but differs in a few ways:
- They never do forward declarations and instead do all includes.
- Seem to be against macros.
- Avoids template metaprogramming while the Epic guidelines seem to use it sparingly.
- Uses Boost while Epic didn't mention it.
- Heavy use of namespaces with very well defined reasons to use them over a class.
All of this seems fairly reasonable. There's honestly more removed than used, which is good.
Common Dislikes
One thing that's common between the Epic and Google guidelines is hatred for RTTI, Multiple Inheritance, and Exceptions. The RTTI is understandable since it can be very expensive if not done right, and doing it right is difficult. Exceptions are a bit harder to completely do away with because C++ simply doesn't have any alternative error handling mechanism except C's annoying error return values. I think if these guidelines are going to be against exceptions they should come out with an alternative to them, or find a way to make them work that avoids all the problems.
Google's guidelines against Exceptions are funny because they list all these pros and cons that don't seem like pros and cons at all. For example, "More generally, exceptions make the control flow of programs difficult to evaluate by looking at code: functions may return in places you don't expect." That's a...con? I guess, but this also sounds like someone who's used to coding in Haskell just not wanting to learn C++. Having coded in tons of languages with exceptions my first thought was, "What are you talking about? You see the try
and it has a block so it always goes to that part of the function. Just...go there."
The C++ Core Guidelines are pretty much what you'd expect from official C++ Standards Committee people:
- You should use everything all the time even if it's not really supported. A great example is how Clang has a bug that makes all of the new
source_location
report line numbers for the logger function not the caller. This effectively makes the new debugging features useless until Clang is somehow forced to fix such an egregious error. Like seriously, how do you screw up logging? - Most of the recommendations are just arbitrary rules about how to name things. Don't capitalize this, make that this long, don't reuse names. Personally I'd rather style guides focus on things that they've seen improve a piece of software's measured quality while its running rather than some arbitrary OCD the lead developer has about names. My main reason for hating these kinds of guides is naming rules end up being the thing mediocre programmers fixate on as a means of proving their worth on the project, and the first thing you'll see is these little trolls writing extensive pre-checkin rules as a means of exerting power over others.
- The Error Handling guidelines are much more reasonable and most likely what I'll use. Rather than say "don't use exceptions" they lay out guidelines on how to use them correctly.
- I also very much appreciate the attempt to start calling out stupid mythology in the C++ world in Non-Rules and myths.
Multiple Inheritance is also another one that's totally understandable. These days I think the standard is to use inheritance sparingly, and avoid multiple inheritance at all costs. I also think 99% of the instances of multiple inheritance are just a misunderstanding of the domain model and how it can be represented using composition better. A very notable version of this is the Entity Component System which most game frameworks seem to push now rather than the old style of classes inheriting traits from parents.
However, Indoctrination Again
Now we come full circle because, remember, I don't like indoctrination. I don't want to have a bunch of people read my C++ course and come out zealots against exceptions, RTTI and multiple inheritance. That's just as bad as telling a student they must use extensive class hierarchies and dynamic type inference all the time. The better way to approach it is to teach why so many guidelines are against these things by showing them how to use it, then how it goes wrong.
Let's take RTTI as an example. I'd want to have a lesson on RTTI that demonstrated the performance hit you'll have and how to avoid it if you need it. With Multiple Inheritance I'd teach how it works, but then show how you almost never need it. With Exceptions, I'd teach them because they're very useful, but I'd throw in many examples of how they go wrong too. I would also include examples of code that does error handling without exceptions since that's very common (as soon as I find a viable demonstration of this).
What's In
With that in mind, here's the rough list of what I think should go in a C++ course for total beginners:
- Getting setup (this is super hard BTW).
- Base language: variables, if-statements, loops, classic structs, expressions, etc.
- Standard library that's mostly used by Google and Epic Standards.
- Memory management but not getting too deep into allocators.
- Strings and how to work with them.
- The most relevant parts of the STL, with warnings as mentioned by Google and Epic.
- I/O facilities, which may be tough since most of the streams seem to be disfavored, but alternatives seem worse?
- Official OOP with multiple inheritance and RTTI to demonstrate why people avoid them.
- Error handling with Exceptions in both the safe and unsafe ways to avoid.
- Smaller useful parts of the standards like
basic_regex
orbitset
.
What's Out
These are subject to change depending on what kinds of projects I include in the course, but I think a rough list is:
- Concurrency. I really don't think the C++ standard concurrency is highly regarded but I may be uninformed there.
- Numerics. Again, I think other libraries are better than the C++ standard ones.
- Language support. Sadly
source_location
is incorrectly implemented in Clang, and coroutines are questionable from my understanding. - Concepts. Again, I don't think many compilers implement these well and I don't see a lot of projects using this.
- Feature test macros. I don't really see many beginners needing this.
- Templates. I may change my mind on this and possibly include a short lesson but honestly looking at code and most standards it seems if templates are used it's very sparingly.
- Metaprogramming. Thankfully I see the C++ world has woken up to how stupid this was, so it's not as common a practice. I might touch on it briefly but probably just avoid it entirely.
Next Step
Now that I've done my research, written a small bit of C++ to re-learn it, and studied as many C++ style guides as possible, I now have a plan for the C++ course. The goal of the course will be two big goals:
- Teach enough C++ that anyone could start making terrible little games, because if you make 100 terrible games you'll eventually be able to make great games.
- Make the course free to read like my original Python course so I can get back to my roots of helping anyone learn to code, but this time in a language that can actually make fun things.
I'll have another essay written up soon talking about this more once I have the full outline and empty starter course up and ready to go. I'll also have to create at least three C++ projects to confirm that I actually can code C++ and that it's a good choice for these goals. If you're interested in watching me do this live, follow me on twitch.tv/zedashaw where I'll be streaming my game dev starting this week.
More from Learn Code the Hard Way
Very Deep Not Boring Beginner Projects
A list of projects that anyone with basic programming knowledge can do in any language, but have a lot of depth and aren't boring to do.
C++ Is An Absolute Blast
Where I try to explain why I feel like C\+\+ is so much fun, and to correct some misinformation.
Just Use MSYS2 You Say?
Debunking idiots on HackerNews who think a total beginner can just 'Use MSYS2' on Windows.
Solving the Worst Problem in Programming Education: Windows
I've created a set of install scripts for Windows that helps people install many different programming languages using standard tools.