Przejdź do głównej zawartości

The pitfall of teaching C++


Many years ago I read a book from Prentice-Hall about object oriented programming. I don't remember exactly when that was - either shortly before starting studies at university or at the very start of the first year there. I read about methods and messages and I analyzed diagrams on which object A was said to be passing a message to object B by the means of calling one of B's methods.

Objects then seemed to me like active, almost living entities able to communicate through this mechanism of message passing (calling each other methods). I was disillusioned to learn later that this was not true. Objects didn't have concurrent lives and the so called message passing turned out to be ordinary, synchronous function call.

(The book contained examples in C++ and Smalltalk; I ignored Smalltalk examples while reading it; I realize now that my first impression of how objects communicate through message passing was, to great extent, true for Smalltalk).

That was the first bad thing I learned about C++.

Now after I've used several different languages based on different paradigms, I learned another bad thing about C++ (and so far that's the latest one): it is still being taught at universities and sometimes it is even the first or the only language being taught (I'm thinking here of studies in general, not necessarily computer science studies).

Is it the right choice to teach this particular language? Especially, if it is chosen just for an introduction to programming and, for some, the only language they will ever program in? In next short paragraphs I will try to persuade you that the answer is: no, it is not the right choice.

Lots of learning related to the language itself, not to programming in general

How constructors are called? In what sequence, when there is inheritance? Why do we have virtual destrutor and how it differs from regular destructor? When a class is abstract and when do we need one? What happens when some of the methods are virtual while some others are not? What results from weird combinations of access modifiers and/or mutliple inheritance?

The knowledge needed to answer all of these questions (and many others) does not allow anybody to actually write a useful piece of code. I agree this knowledge (or at least part of it) is needed to write a decent C++ program, I'm just saying it is not essential to write it, in the sense that there are other pieces of C++ knowledge that are essential, like flow control, and must be learned too in order to write anything useful. In languages like C or Python one only needs to learn the essential things to start programming, there is no or very little things related to the language itself that are necessary to write decent programs.

It takes away all joy

A student tasked with a problem to be solved by implementing an algorithm enjoys the task when he or she can jump instantly to doing a series of experiments, code one part, integrate it with another and run with different input data to test that it finally works.

With C++ it's difficult to do that: there is plenty of things one must care about, like memory management, that one must focus on, apart from focusing on the problem itself. This phenomenon is very clearly visible and can be experienced when one tries to solve a simple algorithmic problem in C++ and then Python or Lisp.

It creates false belief of what programming is about

For those who study something else than computer science using C++ for an introductory course creates an impression that a programmer must take care of a great number of small, complicated, yet very important things to achieve even an easy task (e.g. implement a queue in C++). Consequently, It makes it difficult to imagine that programmers are capable of creating much more advanced applications, web services and graphical interfaces. How do they do it, if even my simple queue implementation had several surprising deficiencies?

It is enough to read this fantastic article by Peter Norvig:
to see that such an amazing thing as a spelling corrector can be written concisely and can be accessible and easy to comprehend to anyone who wishes to learn how it works. It wouldn't be as accessible (and would actually scare off many people), it were implemented in C++, or even in C, in this particular case.

Closing comments

Most of the criticism I expressed against teaching C++ is directed to doing a C++ course on studies other than computer science. It may be a valid course on CS studies, although I know that Carnegie Mellon University removed object oriented programming from CS introductory curriculum.

Many things that I listed could be said about teaching JAVA as the only language on non-CS studies, but JAVA is definitely less complicated both in terms of possible semantics (e.g. no multiple inheritance), has garbage collection and set of tools and libraries is immensly rich and easy to use.

C++ has lost its position that it had in late 90's. For all reasons listed above, I don't think it deserves to be taught such widely as it is today. I believe much more truth about programming can be conveyed with languages such as Python or even "old good" C.


Popularne posty z tego bloga

Unit Testing code with IO file operations (in Python)

We may often come across a piece of code that was written without Unit Tests at all. In addition, the piece of code may be dealing with IO like file writing and reading, which makes it more difficult to Unit Test it when we are trying to refactor and modify. Let's suppose the code in question looks like this:

def writeInitialsToFile(filename, name, surname):
    initials = name[0] + '.' + surname[0] + '.'
    with open(filename, 'w') as file:

def readInitials(filename):
    initials = None
    with open(filename, 'r') as file:
        initials = file.readline()
    return initials

A straightforward and bad idea would be to write a couple of Unit Tests that make use of a real file and simply test the reading and writing. Is therea a better way to test this code?

First of all, we need a way to replace the real file with something else. For both reading and writing we will now have a couple of functions, one that expects a stream fo…

Piotr's Less Obvious Advice on Google Mock: State maintenance

Google Mock provides several ways to maintain state inside mock objects. One way of implementing state maintenance is with SaveArg. Consider the following example.

We have a class Configurator, which allows a caller to set and get values of a parameter:

class Configurator

    virtual ~Configurator() {}

    virtual void setParamX(int n) = 0;
    virtual int getParamX() = 0;

And we have a class Client that calls Configurator's methods and it also has a method incParamXBy, that can be used to increase the current value of paramX by a certain value.

class Client

    Client(Configurator & cfg);
    virtual ~Client() {}

    void setParamX(int n);
    void incParamXBy(int n);
    int getParamX();


    Configurator & _cfg;

incParamXBy internally calls setParamX and getParamX on Configurator:

void Client::incParamXBy(int n)
    _cfg.setParamX(_cfg.getParamX() + n);

Let's assume that the initial value of paramX is A and that we want to increase paramX by…

Piotr's Less Obvious Advice on Google Mock: Returning new objects from a mock

Google Mock provides a way to return newly created objects from a mock method. Suppose we have a  Generator class that is supposed to generate new objects when createNewRecord method is called:

class Generator
    virtual ~Generator() {}
    virtual Record * createNewRecord() = 0;

...and suppose we want to mock this class:

class MockGenerator : public Generator
    MOCK_METHOD0(createNewRecord, Record * ());

Suppose the caller class Client has run method defined as follows:

void Client::run()
    for(int i = 0; i < 3; i++)
        rec_tab[i] = gen.createNewRecord();

We want the mock to return a pointer to a new object each time createNewRecord is called. This is how we can express this in the test code:

TEST(ClientTest, CanRun)
    MockGenerator gen;
    Client c(gen);

    EXPECT_CALL(gen, createNewRecord())
                 //this is equivalent of returning new Record(1,2,3)