Nesting Review

Recalling the basic design of an if structure:

    if (logical condition)
    {
        // do something when condition is true
    }
    else
    {
        // do something when condition is false
    }

We see that there are two branches possible and so we can use such a structure to decide between two alternatives.

But what if we have more than just two alternatives? Let's say we had three alternative actions. Well, logically we see that we can use merely two questions to decide between the three alternatives. We can use the concept of nesting to do something like this:

    if (question one)
    {
        // first alternative
    }
    else
    {
        if (question two)
        {
            // second alternative
        }
        else
        {
            // third alternative
        }
    }

But if we add more alternatives to this structure, it can become unwieldy quite quickly. Here is a sample with a mere six alternatives:

    if (question one)
    {
        // first alternative
    }
    else
    {
        if (question two)
        {
            // second alternative
        }
        else
        {
            if (question three)
            {
                // third alternative
            }
            else
            {
                if (question four)
                {
                    // fourth alternative
                }
                else
                {
                    if (question five)
                    {
                        // fifth alternative
                    }
                    else
                    {
                        // sixth alternative
                    }
                }
            }
        }
    }

If the statements were longer or I were using that horrible <Tab> key (*shiver*), the lines would be already shooting off the side of the screen!

Therefore, we need an alternative style: cascading.

Nesting Redux: Cascading

First we must admit to ourselves that each of the else clauses contains only a single statement: another if structure. Acknowledging that, we can remove the 'unnecessary' braces that surround them:

    if (question one)
    {
        // first alternative
    }
    else
        if (question two)
        {
            // second alternative
        }
        else
            if (question three)
            {
                // third alternative
            }
            else
                if (question four)
                {
                    // fourth alternative
                }
                else
                    if (question five)
                    {
                        // fifth alternative
                    }
                    else
                    {
                        // sixth alternative
                    }

Now there is just a lot of whitespace between us and a nicer style of coding these types of things. Removing the excess spacing between the else and if keywords, we get:

    if (question one)
    {
        // first alternative
    }
    else if (question two)
        {
            // second alternative
        }
        else if (question three)
            {
                // third alternative
            }
            else if (question four)
                {
                    // fourth alternative
                }
                else if (question five)
                    {
                        // fifth alternative
                    }
                    else
                    {
                        // sixth alternative
                    }

Finally, let's scooch the alternatives' bodies back over into the 'main' line of indentation:

    if (question one)
    {
        // first alternative
    }
    else if (question two)
    {
        // second alternative
    }
    else if (question three)
    {
        // third alternative
    }
    else if (question four)
    {
        // fourth alternative
    }
    else if (question five)
    {
        // fifth alternative
    }
    else
    {
        // sixth alternative
    }

Now everything lines up on the left edge of the new casading if structure. (It is supposed to look like waterfalls or some such...*shrug* I thought the original looked more like a waterfall myself, but either way, this form is known as a cascading or cascaded if.)

[clarifying soon...]

Over the Falls in a Barrell

...nicer menu...

Sometimes there are legitimate options to be chosen:

    Menu
    1) Enter information
    2) Sort information
    3) Remove information
    4) Print information
    5) Quit

    Choice:  r

Now what? So they entered 'r', big deal...

We need to make our programs able to handle these situations. Recalling that our average user is not the brightest of folk and that such people are easily overwhelmed by lots of options, we can make a pledge to never have a menu with more than 9-10 choices in it. If your application calls for more choices than that, break them into logical groups and use a 'sub'-menu structure.

Now that we will never have more than a single digit number in front of our choices (even the 10th option can be numbered 0), we more clearly see that we can read the user's choice with a char type variable. For instance, with the above menu structure, the user could type '3', 'R', or even 'r' to indicate they'd like to 'remove information'.

Example: randomly Selected Messages

One relatively easy thing we can do to practice decision making and improve our user interface 'skills' at the same time is to simply have our program display randomly selected messages instead of always stating the same old thing.

First we must come up with several clever and witty rejoinders which all have applicability to the situation. The easiest part of the program would be the closing remarks. Here are a few 'choice' (pardon the pun) remarks we could make at the end of a program dealing with 2D point calculations, for instance:

Then we need to pick one of them at random -- each time the program ends in this case, but remember that this technique can be used for any kind of response messages during the program.

Since there are five messages from which to choose, we'd want to create a random value between 1 and 5 inclusive: [1..5]. Then, look at that value just go down our list sequentially, as it were. Here, let's look at the code:

    which_msg = rand() % 5 + 1;
    if (1 == which_msg)
    {
        msg = "Have a pointilistic day!";
    }
    else if (2 == which_msg)
    {
        msg = "My!  What pointy shoes those are!  Are you an elf?";
    }
    else if (3 == which_msg)
    {
        msg = "Can you point me in the direction of a good delicatessin?";
    }
    else if (4 == which_msg)
    {
        msg = "That's the point...at the top of your head!";
    }
    else
    {
        msg = "I wish someone would have pointed out to me that money "
              "doesn't grow on trees ~before~ I shelled out all that dough "
              "for these saplings!";
    }

Note how we only tested four of the possible values to distinguish among our five possible alternatives! (You always only need n - 1 conditions/questions to verify which of n alternatives is at hand.

Two Ifs Make an And

...if-nesting == &&...

Extracting Efficiency

[clarifying SOON!]

Look At Those Cluttered Branches

Let's look at a typical decision in a program and see if we can't make it work better:

    if (1 == count)
    {
        cout << "Only one widget in stock.\n";
    }
    else
    {
        cout << "There are " << count
             << " widgets in stock.\n";
    }

The display is changed depending on the number of widgets we currently have -- one versus 0 or many (we'll not consider negative inventory here for simplicity). The first thing we notice is that both branches end with a common action: printing " in stock.\n":

    if (1 == count)
    {
        cout << "Only one widget in stock.\n";
    }
    else
    {
        cout << "There are " << count
             << " widgets in stock.\n";
    }

If we'd moved that action to after the if structure, we'd have only needed to place it once -- less typing == fewer errors!

    if (1 == count)
    {
        cout << "Only one widget";
    }
    else
    {
        cout << "There are " << count
             << " widgets";
    }
    cout << " in stock.\n";

Cool! If only we'd thought of that earlier... But after we practice this technique some we'll get the idea and just code like this second version from the start. (This technique is often called re-factoring, btw. Of course it is named after the algebraic concept -- we are factoring out the common parts of all the branches, after all. The 're' part simply refers to the fact that the code was there and is being reworked.)

But, placing ourselves in the user's shoes for a second, we see that it might be easier to follow the program's output if the phrases produced for both cases were more similar. It would help them focus on the location of the numeric value and make scanning such a report easier. Let's try it:

    if (1 == count)
    {
        cout << "There is " << count
             << " widget";
    }
    else
    {
        cout << "There are " << count
             << " widgets";
    }
    cout << " in stock.\n";

Now both branches begin with the same action: printing "There ". So, we re-factor:

    cout << "There ";
    if (1 == count)
    {
        cout << "is " << count << " widget";
    }
    else
    {
        cout << "are " << count << " widgets";
    }
    cout << " in stock.\n";

Now there is no simple re-factoring to left to be done. But, we do see a commonality. In the 'middle' of both branches the same action is taken: printing ' ', the count, and " widget":

    cout << "There ";
    if (1 == count)
    {
        cout << "is " << count << " widget";
    }
    else
    {
        cout << "are " << count << " widgets";
    }

To re-factor this kind of thing, we have to duplicate our if structure! Even though this sounds counter-productive, it isn't a bad thing to examine. Sometimes it can work out better than you'd initially think:

    cout << "There ";
    if (1 == count)
    {
        cout << "is";
    }
    else
    {
        cout << "are";
    }
    cout << ' ' << count << " widget";
    if (1 == count)
    {
        cout << "";
    }
    else
    {
        cout << 's';
    }
    cout << " in stock.\n";

Interesting... Our first if structure is now deciding on verb agreement -- which is a fairly common task for programs concerned with a friendly interface. The second structure seems a bit inefficient with the printing of nothing in the first branch and all (recall that the two double quotes right next to each other represents an empty string). This can be fairly simply fixed by removing that branch entirely:

    cout << "There ";
    if (1 == count)
    {
        cout << "is";
    }
    else
    {
        cout << "are";
    }
    cout << ' ' << count << " widget";
    if (1 != count)
    {
        cout << 's';
    }
    cout << " in stock.\n";

(Note how the condition tested has become the logical opposite of the one from above.)

So, we have one branch fixing verb agreement with subject plurality ("is" vs. "are") and another fixing spelling based on plurality ('s' or not). Those both seem very re-usable for many situations. (Okay, so the 's' thing is fraught with peril because English is SCREWED UP...but it can be enhanced later.) To capitalize on this re-usability, we'd like to make them into functions...but that isn't until Chapter 5. *sigh*

What we can do, though, is realize that as long as we send information to cout in the proper order, the user never needs to know when that information was 'created'. We took advantage of this in previous programs (albeit not as discours-arily) to perform all of our calculations before we displayed the first result. Keeping tasks logically together helps us organize our thoughts -- here a plan about how to solve a problem.

In order to 'calculate' the verb agreement or plurality of our output, we need a place to hold onto those pieces. To store the "is" and "are", we'll need a string type variable. But what about the 's' vs. nothing? What's the best data type to store either a character or ...nothing?! In fact, how do we store NOTHING at all!?!?

Oh...yeah...an empty string! We just talked about that, didn't we? *whew* Sorry...I just get so confused and over-excited sometimes... *breathe* Ahh...much better. Let's go on, shall we?

So, since we can store both a single character and nothing in a string type variable, we just need to have two string variables and then we can pull the decisions out of the cout and remove the redundant condition checking:

    if (1 == count)
    {
        plural = "";
        verb = "is";
    }
    else
    {
        plural = 's';
        verb = "are";
    }
    cout << "There " << verb << ' ' << count << " widget"
         << plural << " in stock.\n";

The fastidious among you will note that we're once again printing an empty string for the case when count is 1. Although this is a bit inefficient, it isn't noteworthy in the context of the general speed of a cout.

Streamlining On Steroids

[clarifying SOON!]

...ternary operator (?:)...

Reasons you can replace your if structure with a question-colon operator:

How do I use it?

    if (condition)
    {
        action value_true
    }
    else
    {
        action value_false
    }

Would become:

    action condition ? value_true : value_false

For example, the verb agreement branch above (the first one) could be changed from this:

    if (1 == n)
    {
        verb = "is";
    }
    else
    {
        verb = "are";
    }

To this:

        verb = 1 == n ? "is" : "are";

The adventurous can also nest ternary operations inside one another to replace cascaded structures. (All of our rules must still apply, however! ALL of the branches must perform the same simple action to like-typed values!) The random message selector above, for instance, could be re-written as:

    which_msg = rand() % 5 + 1;
    msg = (1 == which_msg
          ? "Have a pointilistic day!"
          : (2 == which_msg
            ? "My!  What pointy shoes those are!  Are you an elf?"
            : (3 == which_msg
              ? "Can you point me in the direction of a good delicatessin?"
              : (4 == which_msg
                ? "That's the point...at the top of your head!"
                : "I wish someone would have pointed out to me that money "
                  "doesn't grow on trees ~before~ I shelled out all that dough "
                  "for these saplings!"
                )
              )
            )
          );

Some people find this structure a bit disturbing or even distasteful. Others find it elegant [beyond reason]. Personally, some days I like it and some days I'm not so sure... But I think I like it more days than not, so I'll keep it. *smile*

...simple alter/output decisions...