Janis Lesinskis' Blog

Assorted ramblings

  • All entries
  • About me
  • Projects
  • Economics
  • Misc
  • Software-engineering
  • Sports

The state of C++ education in 2021


I've always been very interested in adult education and also programming languages. As a result of this I've been engaged in this space for a long time. I spent a few years travelling around running Python workshops for a number of companies around Australia and the world and I was reminded of some of the challenges of teaching programming. I think Python is substantially easier to teach than C++ if only because of the fewer layers of abstraction that you have to cover on average when working in the language.

I want to preface this entire article by saying that teaching C++ is hard, I think this is partly due to the fact that the language itself is enormous and partly due to the fact that the language is all about giving maximum power to the users. The power of C++ sometimes manifests in the form of "footguns" that can cause a lot of damage, but the ethos of the language design is to give as much power to the programmer as possible with the responsibility placed on the programmer to get it right. This approach comes a lot of difficulties that you have to navigate. The language is unashamedly aimed at proficient programmers much more so than beginners, something that as a professional developer who's worked on embedded and real time systems I'm often very grateful for when I have to do something very specific.

When you start looking at the language specification something that's immediately obvious is that C++ has grown a lot over the years, the specification for the language is literally thousands of pages long. From an educational perspective this is difficult as knowledge and techniques go out of date over time and the bigger the standard the more burdensome it is to keep up.

This complexity is why it can be hard to explain things like C++'s most vexing parse to those that are new to the language. Then there's all the different syntax that's been added over time, of which some is really hard to search for, like user defined literals or some that's been bolted on later like the lambda syntax.

Both the user defined literals and the lambdas are examples of things that were added in C++11 and as a result older texts might not cover these at all. These features are hard to search for and if you didn't know they existed you might not come across them in your day to day work. The language has changed fairly substantially over the years, and modern C++ design and idioms have a different feel to older versions of the language. And I'm not talking about things like std::auto_ptr which was deprecated in C++11 then removed in C++171 but rather a broader shift in the way in which people use the language and design their code.

A friend of mine was getting started with a new year at his university course he was choosing some subjects. There was a C++ course and I gave the very explicit warning that the quality of teaching of C++ in many universities is quite poor. He wanted to do the course anyway because he wants to understand more implementation details. I think this is a great goal and theoretically a good C++ course could be an incredible avenue to teach people who have some programming experience already some of these concepts. Fast forward a bit and he sends me this picture of a lecture slide:

C++ lecture slide

I get the sentiment here but an issue I see frequently is that many of these courses just don't teach people up to date C++. I think up to date C++ skills will be in demand for some time yet and the ability to deal with legacy C++ code bases as well, but mediocre out of date C++ knowledge is becoming less valuable in the workplace as newer projects are tending to not be in C++ as often. A few years ago I remember a classic example of this, I was spending some time in some programming chat rooms at the time and one day a student from what I would have thought was a reputable college joins the chat with a problem he'd been facing. Someone provided what was a really nice C++11 solution and we couldn't figure out why this wasn't working for the student. We did all the things you'd usually do, we compiled locally, put the code in ideone and Compiler explorer. Everything clearly worked on every compiler we tried, and we tried quite a few.

Eventually we found out the reason the code wasn't working for the student was because he was using a 1990s version of Borland C++ as dictated by his course. Keep in mind that this conversation happened in 2017, this Borland compiler version had been out of support for around 2 decades. While Borland C++ was great compared to the alternatives when it was released two decades is an eternity in this space. To be teaching students using a compiler so egregiously out of date is absurd. The last time I saw Borland C++ media was in the pile of floppy disks that the floppycoasters was using to make coasters:

Borland C++ install media

I mean it's crazy that you have people using this stuff these days, in university courses no less, since it has been years since computers even had floppy drives in them. The most disturbing part of this is that much more up to date and altogether superior alternatives to 1990s era Borland C++ exist now that are free and open source. What makes this even more absurd is that installing Borland C++ is now probably harder than installing GCC/Clang/MSVC or some other modern compiler because its now so far out of date. Getting this to work with external libraries seems like it would be painful.

I'd pleasantly forgotten how out of touch a lot of the C++ courses were until last week when a friend asked a question. In one of the lectures they were saying that if you divide an int with another int you get a float type, he thought this was not correct but wanted to verify since this was said in his course. In other languages sure you might get 2.5 as a result of dividing 5 and 2 but this is obviously wrong in the general case in C++. Thankfully you can directly verify what happens in this case yourself. Unfortunately this sort of downright incorrect teaching creates doubts.

#include <iostream>
int main(int ac, char** av){
    int a = 5;
    int b = 2;
    int c;
    c = a / b;
    std::cout << a << b << c << std::endl;
    return 0;
}

(see this on ideone)

As you can see this outputs 552. If you were to change this code to make c of type float you'd get this:

#include <iostream>
int main(int ac, char** av){
    int a = 5;
    int b = 2;
    float c;
    c = a / b;
    std::cout << a << b << c << std::endl;
    return 0;
}

(see this code on ideone) As you can see this outputs 552.

Now there's a few slightly interesting tangents this can take, like what do we get when we use auto?

#include <iostream>
int main(int ac, char** av){
    int a = 5;
    int b = 2;
    auto c = a / b;
    std::cout << a << b << c << std::endl;
    return 0;
}

The output again is 522 but what is the type of c here? You can use the typeid operator or some other means to verify what the types are here, doing so also is a good learning opportunity in itself:

#include <iostream>
#include <typeinfo>
int main(int ac, char** av){
    int a = 5;
    int b = 2;
    auto c = a / b;
    std::cout << a << b << c << std::endl;

    std::cout << "The type of c is:" << typeid(c).name() << std::endl;
    return 0;
}

When run this has the output:

522
The type of c is:i

(see this on ideone here)

So you can see that auto here deduces the type of c to be an integer. typically you wouldn't usually need to do something like this if you have well written C++ code, but it's interesting that you can do this if you want. Usually typeid is something you'd only really use if you needed to know the exact type in a polymorphic type situation. Deducing the type of a variable that you already knew at compile time is often best done other ways.

Note that nowhere in here is the value of c equal to 2.5.

I understand that keeping up with all the changes in C++ is hard but what I don't quite understand is how university level C++ courses are getting things this badly wrong and it doesn't seem to be an isolated problem either. These are people who are in the business of teaching C++, I think they owe it to their students to get the basics of the language right and to use technologies that are at least from some time in the last decade.

Resources

Here's some things that I think are useful for learning C++ skills:

  • IDEone - online compiler platform, good way to test out code snippets and share with others. This is useful if you are trying to convey concepts with people in a code form and don't want to have to deal with issues like setting up compiler toolchains and whatnot.
  • Compiler explorer - Great way to see what's happening with internals and compiler details, extremely good UI to see the details.
  • Elements of programming by Stepanov and McJones - I think this is an exceptionally well written book that covers a lot of important concepts. This is a very rigorous text and has a very modern feel to it.
  • The Effective C++ series by Scott Meyers, these have a bit of an "old fashioned" feel but still contain some good information about "classic" object-oriented programming in C++. I do think more modern idioms and structures can be better choices in some situations but there's good information in these books.

  1. C++ is somewhat known for not removing things, but this particular case was fairly egregious since you couldn't place std::auto_ptr inside standard containers which made the whole thing a whole lot less useful. After years of telling people to just avoid this entirely I'm glad that this is gone. ↩

Published: Wed 10 March 2021
By Janis Lesinskis
In Software-engineering
Tags: economics IT-industry education c++ software-eduction software-teaching

links

  • JaggedVerge

social

  • My GitHub page
  • LinkedIn

Proudly powered by Pelican, which takes great advantage of Python.