Thursday, February 15, 2018

The Neverending Journey

This time around, instead of writing about some of the experiences made during the process of trying to solve the various programming challenges of this chapter, there is something more important to write about.

The Old Code


If you happen to view any of the solved programming challenges, all those previous to chapter 12, you will likely notice the presence of an #include in the header section of the driver program. This file, called "Utility.h", contains includes and using directives. From the beginning this was a great help in that there was no need to use fully qualified names in any given program. So, instead of having to write:

int main()
{
     std::string namae = "Yuki Mori";
     std::cout << namae << std::endl;

     std::cin.get();
     std::cin.ignore();
     return 0;
}

It was possible to write:

int main()
{
    // Suppose that NUMELS holds 5 elements
    array<string, NUMELS> words { "One", "Two", "Three", "Four", "Five" };

    for (auto countWords : words)
    {
         cout << countWords << "\n";
    }

    cin.get();
    cin.ignore();
}

Comfortable, isn't it? This little header file made it possible to not only write programs a little faster. There is this saying: "There is more code read than written," and as code is written for the human eye,
the second version of code should be a easier to read. Of course, in a very short example, it doesn't matter which way it is written, but when code for a program grows very large, it becomes a different story.

If the end of making code written by this person easier to read for you has been achieved, then it may have been ruined by the fact, that the overuse of comments made it much more difficult ... For that I can only say: Sorry, dear readers and visitors!

Since updating the file on a regular basis, the common header files and the most common using directives found in almost every program became 'second nature.' In other words there was no need to make a concious effort to memorize any of it. A positive side-effect, if you will.

Until today, there was no explanation given for the reason of the existence of this file. Indeed, there would have been another way to both know which header files to include to make a program work, and spare this person the effort of writing code in the way the first example above shows. Here is the very first code example, found in the book on page 28:

1:  // A simple C++ program
2:  #include <iostream>
3:  using namespace std;
4:
5:  int main()
6:  {
7:      cout << "Programming is great fun!";
8:      return 0;
9:   }

You will notice that it is line 3 that brought about the existence of a file called "Utility.h". Being very new to programming then, there were still some things I did know. Never use using namespace.std This was about the first thing I learned while reading around the web, while trying to find out what exactly this line of code does beyond an explanation given in the book. It was a discussion about the reason for not including it, and not so much about what it is and what it does. The gist of this and similar discussions about this particular topic was: "This is evil, don't use it, period!"

It is only natural that a question such as: "Why do many books teach to use: using namespace std;, some written by 'living legends' of the C++ scene, if it is so bad?" is then asked. More seasoned programmers will continue pointing out why it is and why it should be avoided in any case. Instead, one should use:

#include <iostream>
using std::cout;

But what about beginning learners of the language? Why should they care? And what is the reason why almost all books, even those of 'living legends' of the C++ scene, use exactly this line of code in all of their examples?

Exactly because it is targeted at students and learners, not at the production environment, where using namespace std; is discouraged, or banned, and for very good reasons. So, we as learners are 'priviliged' in that we live in blissful ignorance, we can use it. It is alright! Go ahead, do! That is, until the day our eyes are opened, either by doing research on our own, or someone more knowledgeable tells us to stop using it already.

Since this person learned early on that it is bad, so trying to find a different way should be beneficial, in an attempt to find this better solution, Bjarne Stroustrup's book "The C++ Programming Language" contained the necessary idea. He offers learners a file, which he writes: "You should not make an attempt to understand anything that is in there."

Thus, the "Utility.h" file was born, and the reason why it has come into existence. Yet, there is still something both using namespace std; and "Utility.h" have in common. It is the fact that both allow to write code without using fully qualified names. Besides that, using namespace std; eliviates the burden of knowing which using directives to use, if you weren't allowed to use it. Not so with the "Utility.h", as was already mentioned. In short, both are more of a crutch, to ease the burden of learning. Allowing to concentrate fully on code examples and explanations, instead of an added difficulty for having to remember which using directives to use when writing one's own code. 

Eventually there would come a time, in which "Utility.h" had to fall away, so this person thought. This time came with chapter 12, the first chapter about C++ classes. Of course there would have been the possibility of including this header file, but things should take a different turn anyway.

When starting to write code, two changes took place, none of which should be very noticeable if you don't pay attention. In the first, and eventually also in the second programming challenge, fully qualified names were used, and of course appropriate header files were included in each header file that needed them. Soon the realization dawned on this person that by using these fully qualified names, the lines of code would become much longer than they have to be. It was also tedious, and, on top of it, much more difficult to read.

The question 'what to do?' soon found an answer: "Why don't you use using directives? This way you have the best of both worlds, without including anything and everything that is not needed." From then on, all header files included lines like:

#include <array>
using std::array;

#include <string>
using std::string;

Keep the word 'header file' in mind! This is utmost important. Yes, these lines were included in the header file. Before going any further into this particular topic, I have to apologize. The apology is made for the fact of not having mentioned it months ago. Indeed, I planned on doing it, more than once, and everytime an occasion arose, it was forgotten ... Sorry!

Now, you might look and say: "Why is this person apologizing for this in the first place?"

It is because this also is considered very bad practice. This was another thing I was aware of, yet made the concious decision to do it anyway. Reasoning that this is still a learning experience, so no harm is done. Important was only the fact to be aware of it. 

Doing it, maybe even in a header file, where instead one should use fully qualified names, which should at best contain only function definitions, and only the smallest handful of inline functions, and to keep all the rest in the implementation or driver file, including additional includes, is bad. A little less bad than using namespace std; but not much better in any case. Being aware of it, doing it, and not warning about this - in any scenario that is outside the learning environment, is very bad and highly discouraged. Hence the sincere apology!


This is another change that has taken place, and it is one for the better. Letting go of this practice, that, even knowingly and well aware of the potential risk it carries, turns into a very bad habit!

Having written all this, it is now time to turn to the current chapter. For the first time in a long time it was possible to solve more than one challenge in a short amount of time. Maybe it was because the challenges weren't very difficult. Maybe it was because some of the challenges were very interesting. The Time Format and Time Clock classes for instance. Also the FileFilter class to name another one.

The Here And Now


There was only one challenge exception: Programming Challenge 15.13 - 'Pure' Abstract Base Class Project. If you have seen the headline to the solution of this challenge, you will may have noticed the single quotation marks around the word Pure. It is for the fact, that, despite its title, this project is not the least bit about 'Pure Abstract Classes.' If it were, the problem statement would have been different. There would also had to have been at least one example in one of the main chapter's subsections. It is a misnomer at best, and on top of it contains an error, which is to be found in the problem statement:

Define a pure abstract base class called BasicShape. The BasicShape class should have the following members:

Private Member Variable:
area: A double used to hold the shape's area.

Can you find the errors? Forget about the word 'Pure' for a moment, and pay attention to the word Private. This should be the access modifier. Now consider that this class should be inherited from. Keeping strictly to the problem statement's restrictions, which in this case would be:

One private member variable

There is no mention of adding anything, as is shown in the second example included in the solution to this challenge. Without adding something to the class, the problem becomes unsoluble. This, and it not being a 'Pure Abstract Base Class' in any way, made this challenge the first one to 'solve and forget.' It should turn out that, discussing this problem, and being helped in understanding better what a 'Pure Abstract Class' is, and whether or not this concept even exists in the language, this person's eyes were opened to many things.

In the end, what was considered the first truly bad challenge, turned out to be the key to realize many things important to this person's future of learning. The challenges, as mentioned, weren't difficult to solve at all. And even this one would have taken no more than half an hour to solve, had there not been the poor naming, and the 'private' member restriction. This, ultimately, had to make way for the protected access specifier.

Reading 'Think Like A Programmer' written by V. Anton Spraul. Having done this, he would likely consider the program being 'Kobayashi Maru.' To quote from the book:

"For programmers, then, we can define problem solving as writing an original program that performs a particular set of tasks and meets all stated constraints. Beginning programmers are often so eager to accomplish the first part of that definition—writing a program to perform a certain task—that they
fail on the second part of the definition, meeting the stated constraints. I call a program like that, one that appears to produce correct results but breaks one or more of the stated rules, a Kobayashi Maru."

If you got curious, you may also like the video-series to be found at youtube, created by the author of the book. (Please enjoy)




For this person it is now time for a break, and a fresh start with the next chapter. The wish for it being all downhill from this point onward still stands. Please keep your fingers crossed. As always, my thanks goes out to all visitors, old and new. Thank you for paying this humble blog a visit! To my fellow students, my hope is that you are taught better programming principles and practices, and consequently follow and obey them. I also hope that, if you haven't already, you as well will be done with this chapter soon.

No comments:

Post a Comment