# Lab 6: Selection

## Introduction

One of the easiest ways to make a program user-friendly is to make it menu driven. That is, rather than prompting the user in some vague sort of way, we present them with a menu of the choices available to them. Then all the user has to do is look at the menu and choose one of the choices. Since the menu always tells the user what their options are, the user needs no special knowledge, making such a program easy to use.

For example, a simple 4-function calculator program might prompt the user by providing the following menu:

```Please enter:
- to subtract two numbers.
* to multiple two numbers.
/ to divide two numbers.```
Thanks to the menu, a user knows exactly what to enter.

This lab's exercise is to complete such a program, and at the same time learn about some of the C++ control structures for selection.

## Old Code

Let's first take a look at some old code. In the previous lab, we looked at this function:

```string pluralize (string singularNoun)
{
int lastCharIndex = singularNoun.size() - 1;
char lastChar = singularNoun[lastCharIndex];
if ((lastChar == 's') || (lastChar == 'x'))
return singularNoun + "es";
else if (lastChar == 'y')
{
string base = singularNoun.substr (0, lastCharIndex);
return base + "ies";
}
else
return singularNoun + "s";
}```

This function used a multi-branch `if` to decide which rule to apply in making the noun plural.

### General `if` Statement

The general pattern for an `if` statement looks like this:

```if ( `Condition` )
`Statement1`
[else
`Statement2` ]```

Either `Statement1` or `Statement2`, but not both, are executed based on the value of `Condition`. If `Condition` is `true`, then `Statement1` is executed; otherwise (i.e., `Condition` is `false`), `Statement2` is executed.

The square brackets `[...]` in the pattern indicates that the `else` clause is optional. Sometimes a simple `if`, without an `else`, is all we need.

### Multi-branch `if` Statement

We can also chain several `if`s together into one statement. Now generally it's not advisable to put an `if` statement in as `Statement1` of another `if`. These can get confusing. However, using an `if` statement for `Statement2` is perfectly acceptable---encouraged, even. In general, a multi-branch `if` looks like this:

```if (`Condition1`)
`Statement1`
else if (`Condition2`)
`Statement2`
...
else if (`ConditionN`)
`StatementN`
else
`StatementN+1````

Consider the pluralizer above. There are four possibilities for the singular noun: it ends in an 's', it ends in an 'x', it ends in a 'y', or it ends in something else. This chain of rules/conditions leads to a chain of `if`s.

Exactly one of the `StatementI` will be executed. It will be the first `StatementI` where `ConditionI` is `true`. All of the previous conditions must be false. If all conditions fail, then the fail-safe `StatementN+1` is executed. This is exactly what we want and need for the pluralizer; you'll also need it for the code in this lab.

 Helpful hint: Include a fail-safe `else` in a multibranch `if`, even if it's just a debugging statement.

The debugging statement can be as simple as a statement that prints an error message like "This statement should not print". This will make things much easier for you to debug your program when (not if) something goes wrong.

Also, there is no condition after the last `else`.

 Helpful hint: The last `else` in any `if` statement should not have a condition test.

When any `else` clause is triggered, we know that the previous test failed, so there's no need to make a further test. For example, we could write:

```if ((lastChar == 's') || (lastChar == 'x'))
return singularNoun + "es";
else if ((lastChar != 's') && (lastChar != 'x') && (lastChar == 'y'))
{
string base = singularNoun.substr (0, lastCharIndex);
return base + "ies";
}
else if ((lastChar != 's') && (lastChar != 'x') && (lastChar != 'y'))
return singularNoun + "s";```

But the extra tests in this version are completely unnecessary. When any of the `!=` tests are evaluated in this new multi-branch `if`, they will always be true because they only made after the corresponding `==` tests were discovered false. This is why the original version of `pluralize()` does not have these unnecessary `!=` tests.

### Compound Statements

The patterns above for the `if` and multi-branch `if` statements were carefully crafted. In particular, we used the singular "`Statement`", not "`Statements`". We can put only one statement in those places in the patterns.

What if we need more than one statement? Well, that's exactly what we needed with the second rule for pluralizing a word which involves two statements. C++ allows us to wrap several statements in curly braces and treat them as one:

```{
`Statement1`
`Statement2`
...
`StatementN`
}```

So that's why there are those curly braces around the two statements for the second rule. If we dropped them, then the compiler would get confused over the last `else` since there isn't a corresponding `if` close enough for it.

## Files

Directory: `lab6`

Create the specified directory, and copy the files above into the new directory. Only `gcc` users need a makefile; all others should create a project and add all of the `.cpp` files to it.

Add your name, date, and purpose to the opening documentation of the code and documentation files; if you're modifying and adding to the code written by someone else, add your data as part of the file's modification history.

## Looking at the Code

Take a few moments to study `calculate.cpp`, particularly the code in the `main()` routine. Make sure you understand the purpose of each statement in `calculate.cpp` before going any further in this lab.

Ignoring its error-checking code, `main()` should behave like so:

Our program should display on the screen a greeting, followed by a menu of permissible operations. It should then read a user-specified operation from the keyboard. It should then prompt the user for the two operands for that operation, and then read those operands from the keyboard. It should then compute the result of applying the user-specified operation to the two operands. It should conclude by displaying that result on the screen, with appropriate labeling.

All of this behavior is coded up in `main()` expect for the sentence written in boldface. Since there is no predefined C++ capability to directly perform that operation, we will write a function `apply()` to do that action. This function is (arguably) useful beyond just this program, so we'll put it off in a library.

## Function Design

As usual, we use object-centered design to develop this function.

Behavior. Our function must apply `operation` to `op1` and `op2` and return the result. We can describe the needed behavior as follows:

Our function should receive from its caller an operation, and two operands. If the operation is `'+'`, our function should return the sum of the two operands. If the operation is `'-'`, our function should return their difference. If the operation is `'*'`, our function should return their product of the two operands. If the operation is `'/'`, our function should return their quotient.

Objects. From this behavioral description, we can identify the following objects:

Description Type Kind Movement Name
The operation `char` varying received `operation`
One of the operands `double` varying received `op1`
The other operand `double` varying received `op2`
The sum of the operands `double` varying out `op1 + op2`
The difference of the operands `double` varying out `op1 - op2`
The product of the operands `double` varying out `op1 * op2`
The quotient of the operands `double` varying out `op1 / op2`

From this list, we can specify the behavior of our function as follows:

Specification:
receive: `operation`, a `char`; `op1` and `op2`, two `double` values.
return: the `double` result of applying `operation` to `op1` and `op2`.

 Helpful hint: Do not name the first parameter `operator`. It's a keyword, and the compiler may not give you the best error messages if you do use it as a variable.

Using the specification (and heeding the hint), add a prototype for a function named `apply()` in `mathops.h` and a stub in `mathops.cpp`.

Function Operations From our behavioral description, we have these operations:

Description Predefined? Name Library
Receive `operation` (a `char`) yes function call
mechanism
built-in
Receive `op1` (a `double`) yes function call
mechanism
built-in
Receive `op2` (a `double`) yes function call
mechanism
built-in
Return the... yes `return` built-in
...sum of `op1` and `op2` yes `+` built-in
...difference of `op1` and `op2` yes `-` built-in
...product of `op1` and `op2` yes `*` built-in
...quotient of `op1` and `op2` yes `/` built-in
Do exactly one of math operations yes `if` statement built-in

C++ provides facilities for performing each of these operations as noted in this chart. The last operation is different from the others, in that it requires selective behavior. We can use the `if` statement.

Function Algorithm. We can organize these operations into the following algorithm:

1. Receive `operation`, `op1` and `op2`.
2. If `operation` is '+':
Return `op1` + `op2`.
Otherwise, if `operation` is '-':
Return `op1` - `op2`.
Otherwise, if `operation` is '*':
Return `op1` * `op2`.
Otherwise, if `operation` is '/':
Return `op1` / `op2`.
Otherwise,
Print an error message and return 0.

From this algorithm it is clear that a multi-branch `if` will do the trick. The last case is technically unnecessary since our program checks the operation, but as noted above you shouldn't rely on that. Print out an error message here so that it's very clear that something went wrong. If you want, you can even quit the program (with `exit(1);`) instead of returning 0, which is merely an arbitrary value in this case.

Add a multi-branch `if` to your `apply()` stub to encode this step.

Testing and Debugging.

When you are done, compile everything and test your program. Fix it up until it works correctly. Be sure to test each operator at least twice.

## Coding 2: The `switch` Statement

The multi-branch `if` suffers from one drawback:

• To perform the addition operation, one condition is evaluated: `(operation == '+')`.
• To perform subtraction, two conditions are evaluated: `(operation == '+')` and `(operation == '-')`.
• To perform multiplication, three conditions must be evaluated: `(operation == '+')`, `(operation == '-')`, and `(operation == '*')`.
• And so on...

In general, selecting `Statementi` using a multi-branch `if` statement requires the evaluation of i conditions. This can be good because we can assume that the failed test did, in fact, fail. When testing for ranges of values, this is incredibly useful (and even necessary).

On the other hand, the evaluation of each condition consumes time, statements that occur later in the multi-branch `if` statement take longer to execute than do statements that occur earlier. It would be great if we could avoid this if at all possible. One possibility is using a `switch` statement.

A `switch statement` looks like this:

```switch ( `ConstantExpression` )
{
`CaseList1`
`StatementList1`
`CaseList2`
`StatementList2`
...
`CaseListN`
`StatementListN`
default:
`StatementListN+1`
}```

`ConstantExpression` is any C++ expression that evaluates to a integer-compatible constant. Each `StatementListi` is a sequence of valid C++ statements. Each `CaseListi` is one or more cases of the form:

`case `Constant` :`
`Constant` is an integer-compatible constant.

That's a fair bit of code. Watch the careful use of terminology here, particularly "integer-compatible constant". Let's first figure out what a `switch` statement does:

1. The `ConstantExpression` is evaluated.
2. If the value of the expression is present in `CaseListI`, then execution begins in `StatementListI` and proceeds, until a `break` statement, a `return` statement, or the end of the `switch` statement is encountered.
3. If the value of `ConstantExpression` is not present in any `CaseListI`, then the (optional) default `StatementListN+1` is executed.

A given `Constant` can appear in only one `CaseListi`.

 Helpful hint: Just as a multi-branch `if` should always have a fail-safe `else` clause, you should always have a `default` case in a `switch` statement, even if it just prints an error message.

Perhaps the trickiest thing about a `switch` statement is the purpose of the cases. The cases of the switch statement are merely labels for the compiler to tell it where to start executing code. Consider this code:

```switch (i)
{
case 0:
cout << "Hi ";
case 1:
cout << "there, ";
default:
cout << "people!";
}```

Then, if `i` is 0, this prints

`Hi there, people!`

The cases tell the compiler where to start executing the code, not when to stop. While this is useful in some situations, it won't be for us. When I make a noun plural, I want to apply only one of the rules. When I add two numbers together, I don't also want to multiply them. To stop executing the code at the end of a statement list, we can the statement list with a `break` statement, a `return` statement, or a call to `exit()`.

We've used `return`s for returning values from a function. We've also use the `exit()` function for stopping the program in case of an error. The `break` statement is even simpler:

`break;`

 Helpful hint: The statement list of every case list in a `switch` statement should end with a `break`, a `return`, or an `exit()`.

So when would we use a `switch` statement? Whenever we can. Unfortunately, there are a few restrictions:

• Each `case` must be a constant.
• The `ConstantExpression` and the case values must all be integer-compatible.
• Finding a matching `case` is done only through equality tests.

The integer-compatible data types in C++ include `int` (of course), `char`, and `bool`. It does not include `double` or `string`. That's very important, so maybe you should read it again, this time out loud: "integer-compatible" does not include `double` or `string`.

Consider the chart below. If we write the algorithm on the left, we can use the `switch` in the middle which is equivalent to the multi-branch `if` on the right:

 ```Set `Variable` to `ConstantExpression`. If (`Variable` is equal to `Value1`) then `StatementList1` Else if (`Variable` is equal to `Value2`) then `StatementList2` ... Else if (`Variable` is equal to `ValueN`) then `StatementListN` Else `StatementListN+1` End if.``` ```switch (`ConstantExpression`) { case `Value1`: `StatementList1` break; case `Value2`: `StatementList2` break; ... case `ValueN`: `StatementListN` break; default: `StatementListN+1` }``` ````Variable` = `ConstantExpression`; if (`Variable` == `Value1`) { `StatementList1` } else if (`Variable` == `Value2`) { `StatementList2` } ... else if (`Variable` == `ValueN`) { `StatementListN` } else { `StatementListN+1` }```

A `switch` statement is more efficient than the multi-branch `if` statement because a `switch` statement can select `StatementListI` in the time it takes to evaluate one condition. The `switch` statement thus eliminates the non-uniform execution time of statements controlled by a multi-branch `if` statement. But since the `switch` statement has so many restrictions on it, we use it only occasionally.

We have a slight wrinkle with `pluralize()` because it's first test actually tests two things. However, both tests are equality tests with constants and one variable. We can use two cases for one statement list in a `switch` statement.

So we could rewrite `pluralize()` like so:

```string pluralize (string singularNoun)
{
int lastCharIndex = singularNoun.size() - 1;
char lastChar = singularNoun[lastCharIndex];
switch (lastChar)
{
case 's':
case 'x':
return singularNoun + "es";
case 'y':
string base = singularNoun.substr (0, lastCharIndex);
return base + "ies";
default:
return singularNoun + "s";
}
}```

We're careful in this code to end each statement list with a `return`. Each `case` has an integer-compatible (i.e., `char`) constant.

Try it out for yourself,

1. Copy the multi-branch `if` version of `apply()` so that you have two copies of it in the same file.
2. Rename one of them to be `apply2()`.
3. Now replace the multi-branch `if` in `apply()` with an equivalent `switch` statement. (Leave `apply2()` alone.)
Translate and test what you have written.

When everything is working right, save your work and print a hard copy of your code.

## Submit

Turn in your code and sample runs that proves your calculator works for all operations.