What If?

Sometimes you just can't predict exactly what the user will do:

    Enter a negative number:  4

We obviously can't work with the 4 since it is not negative as requested.

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.

Doing This In Code

The most basic way to code such decisions in C++ is with the if structure. It is one of a group of branching or decision making structures in the C++ language. Its basic format is:

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

Only the block of the if or the block of the else is executed -- never both and never neither. For example, let's say that you had the following code in your program:

    if (x > 4)
    {
        z = 8;
    }
    else
    {
        z = 4*x;
    }

When the value of the variable x is strictly greater than 4, the variable z will be assigned the value 8. Otherwise (i.e. when the value of x is 4 or less), z will be assigned 4 times the value of x. So, given the following situations, you'd have the corresponding outcomes:

    x      z assigned
   -------------------
    1       4
    2       8
    3       12
    4       16
    5       8
    6       8
    62      8
    0       0
    -2      -8

Not all is exactly as you might expect, but it is as the code stated. (The divergence comes from the human expectation that most numbers are positive. We know about 0's and negative values, but we don't like to think of them entering our calculations.)

Note that never is z assigned both 8 and 4*x at the same time. Which assignment is executed will depend on the value of x as the if structure is reached during the program execution.

But I Don't Have 2 Options

Sometimes you just don't have multiple options -- not even two. For instance, suppose the user is entering that x variable above and we want to avoid those 0's and negatives. We can fix them by this code:

    cin >> x;
    if (x <= 0)
    {
        x = 1;
        cout << "Positive values only:  setting x to 1!" << endl;
    }

The alternative (the else) here is that x should remain the value the user entered. We could show that by an else phrase like:

    else
    {
        x = x;
    }

But this is redundant and will simply waste our time, the compiler's time, and the user's time. Why bother?

Essentially, whenever you are faced with either an empty alternative or a useless alternative, simply leave it off. The one place this is troubling is when you think of a situation like this:

    if (x > 0)
    {
        x = x;
    }
    else
    {
        x = 1;
        cout << "Positive values only:  setting x to 1!" << endl;
    }

Here the condition makes the if/true block the redundant one. The way to remove it is to logically negate the condition. The logical opposite of > is <= (don't forget the 'equal to' part!):

    if (x <= 0)
    {
        x = 1;
        cout << "Positive values only:  setting x to 1!" << endl;
    }

Application: bool Default Arguments

With a defaulted bool argument and an if structure, you can make your functions even more reusable. Take, for instance, the print_money() function we wrote a while ago:

    inline void print_money(double amount, char symbol = '$')
    {
        cout.setf(ios_base::fixed);
        cout.setf(ios_base::showpoint);
        cout.precision(2);
        cout << symbol << amount;
        return;
    }

What if we wanted to use this function in a country/region where the monetary symbol is normally printed after the amount? We couldn't! But, with a new default argument and some if help:

    inline
    void print_money(double amount, char symbol = '$', bool sym_aft = false)
    {
        cout.setf(ios_base::fixed);
        cout.setf(ios_base::showpoint);
        cout.precision(2);
        if (!sym_aft)
        {
            cout << symbol << amount;
        }
        else
        {
            cout << amount << symbol;
        }
        return;
    }

Now the caller can determine not only what the monetary symbol is, but also its placement relative to the monetary amount! So, if the caller does this:

    print_money(price*tax_rate);

They'll get their cost printed with a '$' in front of it on-screen. But if they do this:

    print_money(price*tax_rate, '¥');

They'll get their cost printed with a yen-sign in front of it. Finally, if they call our function this way:

    print_money(item_cost, '$', true);

They'll get their cost printed with a '$' at the end of it.

That 'true' sitting in the [actual] argument list seems a bit odd and potentially perplexing, though. Let's make that seem more natural. To do this, I'll provide the caller with some symbolic constants for whether the monetary symbol goes before or after the monetary amount:

    const bool MONEY_SYMBOL_BEFORE = false,
               MONEY_SYMBOL_AFTER  = true;
    inline
    void print_money(double amount, char symbol = '$',
                     bool sym_aft = MONEY_SYMBOL_BEFORE)
    {
        // rest as before...
        return;
    }

Now that last call might look something like:

    print_money(item_cost, '$', MONEY_SYMBOL_AFTER);

Which reads much more nicely than before.

This technique is the beginnings of what programmers call flags or flagging. Basically, the truth/falsity of the sym_aft [formal] argument is acting like a flagger on a road construction crew. The flagger can be telling drivers to go slow or to stop. The sym_aft argument can be telling the function to print the symbol before or after the amount.

Of course, we don't normally use a bool to handle this, we actually would store many flags in a single [long] integer and use the mysterious and verboten &, ¦, ^, and ~ to manipulate/examine them. We'd still provide symbolic constants for the states of each flag, but we'd most likely use an enumeration to do it. All of these advanced flagging techniques can wait, though, until later (like next semester in CSC122).

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 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.)

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 us focus on the location of the numeric value and make scanning 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". 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 (note 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 again 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, let's make them into functions!

We'll need a function that decides on one of two text phrases based on whether a numeric argument is 1 or not. That implies that the return type should be string (as we discussed earlier). The numeric argument will most likely be a whole number, but we're not sure if the system needs to handle only unsigned quantities or signed as well. Well, we can always overload it, right?

    inline string plural(long n)
    {
        string s;      // set to "" by default
        if (1 != n)
        {
            s = 's';
        }
        return s;
    }

    inline string is_are(long n)
    {
        string verb;
        if (1 == n)
        {
            verb = "is";
        }
        else
        {
            verb = "are";
        }
        return verb;
    }

(Overloading for unsigned long is left as an exercise for the reader. *grin*)

Now we just need to use these functions in our stock report:

    cout << "There " << is_are(count)
         << ' ' << count << " widget"
         << plural(count) << " in stock.\n";

Wow! That made quite a difference in our report code! Now the whole thing is a seemless cout statement. No breaks for if structures are visible. (They are still there, but hidden by the function calls!)

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.

Now the only thing left to do is those unsigned overloads and to place the plurality functions in a library...hmm...how about plurality.h? Sounds good to me!

NOTE: More to come...

But I Have More Than 2 Options

...nesting...

...first menu...

Over the Falls in a Barrell

...else-nesting == cascading...

...nicer menu...

Two Ifs Make an And

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

Equal One, Equal Two, Equal ...

When you have a cascaded if structure that meets certain criteria, it can be replaced by a switch structure. A switch structure not only takes less typing overall than an equivalent if structure, but also tends to execute faster -- making it beneficial to both you and your user. (And after you've gained some experience at using/making switch structures, you'll begin to simply see them instead of if's in certain places/applications.)

The conditions under which a cascaded if structure can be replaced by a switch structure are:

To form the switch structure, take the common expression out and place it once in a pair of parentheses after the keyword switch. Now, inside a pair of braces below this line, place the keyword case followed by a single one of the const/literal expressions and then a colon (:). Repeat for each const/literal expression. Place the keyword default and a colon in the stead of the else.

After a (set of) case label(s) that match up with an if test('s ¦¦'d =='s), place the code for that branch (indented, preferably) followed by a 'break;' statement. (This is the only place you should ever use a break, btw!)

Here's a general pattern to follow:

    if (lit_const_expr_1 == common_expr)
    {
        A
    }
    else if (lit_const_expr_2 == common_expr ¦¦
             lit_const_expr_3 == common_expr)
    {
        B
    }
    else if (lit_const_expr_4 == common_expr)
    {
        C
    }
    else
    {
        D
    }

Would become:

    switch (common_expr)
    {
        case lit_const_expr_1:
            A
            break;
        case lit_const_expr_2: case lit_const_expr_3:
            B
            break;
        case lit_const_expr_4:
            C
            break;
        default:
            D
            break;
    }

The switch evaluate's the common expression once and then quickly looks at the cases in order until it finds a match (equality, remember?) or runs out of cases. If it runs out, it executes any code in a default case. If it finds a match, it begins running there (case labels don't do anything as they 'execute'). Once it is running in a case (default or labeled), it keeps running until it hits a break statement or runs off the end of the switch's block (braces). (Because of this, the last case doesn't actually need a break statement. It is not a bad idea to have one there, however, for reasons of style, easier maintenance, and clarity.)

...slick menu...

Streamlining Gone Insane!

...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:

    inline string is_are(long n)
    {
        string verb;
        if (1 == n)
        {
            verb = "is";
        }
        else
        {
            verb = "are";
        }
        return verb;
    }

Could become:

    inline string is_are(long n)
    {
        string verb;
        verb = 1 == n ? "is" : "are";
        return verb;
    }

Which, of course, we would streamline even further to:

    inline string is_are(long n)
    {
        return 1 == n ? "is" : "are";
    }

to avoid that local variable creation, filling, copying, and removal.

...simple alter/output decisions...