C++ requires you to think after a copy/paste

A lot of copy paste is still inside some of my projects, too. Well yes, I understand. Starting to understand C++ and then be confident requires years. And good code examples, and advice on that path are often priceless.  But you also know that without proper C++ education and sound grasp of key concepts, copy paste will not take you very far. You are capable of abstract thinking and you want to deliver solid C++ code.

So let me show you how applying this kind of thinking can produce much better C++ while refactoring your daily copy/paste dose from Stack Overflow.

So here we go.

As a random starting point, we shall take this article from good old Wikipedia. You have decided to design your C++ code before coding and that is commendable. You have also decided, based perhaps on some Stack Overflow comment by someone, to investigate this “Policy Based Design”.  The article is pretty clean and simple and it also contains an obligatory C++ code example. Ready to be slurped up and incorporated into your design.

For the purpose of this post, I will focus only on the HelloWorld class as presented in there, and take you trough thinking AND refactoring steps to considerably improve the result. In both clarity and usability of the current last release in here.

Ok, this is the original code.

The article explains the rest. We focus on the code above. What I have noticed and disliked first is the API this produces.

It requires users to compose the class from other classes, by inheritance. Before being able to use anything.  And as we all know class inheritance is a bad thing.

And this is even less logical when we apply our thinking and we realize that default language is English and that HelloWorld is very often just used as it is, without switching to other languages. So let us “design in”, this realization we have just made.

While “at it”we have also realized that UNICODE is what anybody will want most of the time so we can safely introduce WideWriterPolicy as our default one.  So here we are. the first step on our “think and refactor trip” has produced better API and thus improved the comfort of its users.  Making them less error prone. Just instantiate the default class which in English language strings output as Unicode … No need to remember anything else, Just use and go.

A deeper dive

That was a bit of a thinking applied and a bit of a basic C++ templates knowledge used. But we can do much better than that. Going further, I have to say I do not like multiple inheritances at all. Or any kind of inheritance. “Diamond problem” and the such.  Just say No.  So why do we have it here?

I might be so bold to advise you to do a short detour to my post on why the class inheritance is bad.  These days modern C++ templates are giving brittle composability of the solution and that is a good thing.  We compose the solution out of parts and make it obvious to the user, in the code. Inheritance is not required for that. Inheritance makes the inheritors bloated with inherited stuff.  It gives them a lot of what they do not need.

In this case, a classHelloWorld will inherit whatever is in the base policy classes. And nobody has guaranteed they will not grow to be large. And it uses just one method from each of them.  And the policy classes inherited might grow and get heavy and complex. Making the life difficult for the  developers using the inherited classHelloWorld.

And then this using declarations. Yet another C++ artifact from the past. These are so-called “access declaration”. Deprecated in modern C++, so the author has added the “using” keyword. , in essence, fighting with name resolution interlaced with template inheritance.

I think you are by now enough of the theory. Here is the next improvement.

Inheritance is removed. And suddenly it is wondrously obvious how unnecessary it was. Template arguments are just nice compile time typedefs. Since there is no inheritance we do not need qualified member access declarations to enforce the access to the required methods from the base classes. We do not need the using’s from above that is.

It is perhaps not your favorite bed-time reading but do some casual stroll through standard C++ library code. It is 99% this kind of design. Templates, default template arguments, and no inheritance. Alex Stepanov was really ahead of it’s time. And still is.

But wait! What are these two static’s inside the run() method?!

Always limit the class members

Eh? What is this C++ “salto-mortale” now, in there? Ok, let us go step by step through this last improvement. What are the “members”? Without ISO terminology and language escapades, I would propose a simple definition:

Member is anything that is not a class or object, method.

And what this has to do with that two statics above inside the method run? What other ways of using methods of  Language Policy and Output Policy we have?

Well, perhaps the “default” C++ idiom, that springs to mind, might be:

Two “normal” class members. Nicely made private and then simply used from inside run().  Here are the problems with this design.

  • HelloWorld class size has grown
    • It got two more members.
    • Each instance of that class will be that much bigger, increasing the size of the applications using it.
  • Proper class members treatment in modern C++
    • Moving semantics have to have code taking care of this two members also
      • Are they both moveable? Swappable?
    • Class copying has to contain code, taking care of this two members too
      • Are they both copyable?

Ok, says you, sod this, I can make them both static. And then you think as I advised you to. Each instance of the HelloWorld class does not need her own policy instances, after all. The statics approach creates two instances per class, not per object.  Ok, says I, that is better, but still, it will make the final app bigger. Many (hundreds) different objects can use these two policy objects. And not every one of them will be used at runtime.  And yes, these two policy classes will also have to be resilient in the presence of multiple threads.

You are thinking and refactoring and you propose “a clever solution”:

By using the default arguments feature you instantiate both policy class upon caller calling the run()  method. Voila : No class members! My comment: this makes instances of two classes once per every call of the run() method.  This can slow down the code considerably, it all depends on the time and resources required to instantiate the policy classes. No members true, but different problems introduced.

Instead, I have designed my code to do nothing until the run() method is called.

There are no new class members, and class copying and moving and constructing and destructing, all are the same as before. At runtime upon the first call, inside a run method, two static instances will be made. On each subsequent call, they will be just used. This is a good thing and this is called “lazy instantiation”. Do not make something if it is not used. Make it on first use only.

Conclusion

The code above is by no means  a “final” solution. I have kept it deliberately at the safe distance from (too much) of C++14, C++17 and standard library abstractions. Yet we have learned a lot, and we have some useful code.

Say No to copy paste!

Of course, do not forget to add error checking before you publish it :)