PCP − Lecture 10

Fall 2020

Clément Aubert

October 8, 2020

Last Time - Introducing Decision Structures

if-else-if Statements

if (<condition 1>)
{
    <statement block 1> // Executed if condition 1 is true
}
else if (<condition 2>)
{
   <statement block 2> // Executed if condition 1 is false and condition 2 is true
}
...
else if (<condition N>)
{
    <statement block N> // Executed if all the previous conditions are false and condition N is true
}
else
{
    <statement block N+1>  // Executed if all the conditions are false
}

Note that the conditions could be really different, not even testing the same thing!

Example

We can make an example with really different conditions, not overlaping:

if (age > 12)
    x = 0;
else if (charVar == 'c')
    x = 1;
else if (boolFlag)
    x = 2;
else 
    x = 3;

Try to give various values to age, charVar and boolFlag, and see which value would x get in each case.

Boolean Flags

Remember that a boolean flag is a boolean variable? We can use it to “store” the result of an interaction with a user.

Assume we want to know if the user work full time at some place, we could get started with:

Console.WriteLine("Do you work full-time here?");
char ch = Console.ReadKey().KeyChar; // Note that here, passing by, we are using a new method, to read characters.

if (ch == 'y' || ch == 'Y')
     Console.WriteLine("Answered Yes");
else if (ch == 'n' || ch == 'N')
     Console.WriteLine("Answered No");
else
     Console.WriteLine("Said what?");

But we can’t accomodate this 3-party situation (you either work here full-time, or you don’t), so we can change the behaviour to

if (ch == 'y' || ch == 'Y')
     Console.WriteLine("Answered Yes");
else
     Console.WriteLine("Answered No");

We’ll study user input validation, that allows to get better answers from the users, later on.

But imagine we are at the beginnig of a long form, and we will need to re-use that information multiple times. With this previous command, we would need to duplicate all our code in two places. Instead, we could “save” the result of our test in a boolean variable, like so:

bool fullTime;
if (ch == 'y' || ch == 'Y')
    fullTime = true;
else
    fullTime = false;

If you looked at the ? operator in lab, you can even shorten that statement to:

fullTime = (ch == 'y' || ch == 'Y') ? true : false;

Why stop here? We could even do

fullTime = (ch == 'y' || ch == 'Y');

Tada! We went from a long, convoluted code, to a very simple line! We already did this trick last time, but I thought that seeing it again would help.

Constructing a Value Progressively

In lab, last time, you were asked the following:

Ask the user for an integer, and display on the screen “positive and odd” if the number is positive and odd, “positive and even” if the number is positive and even, “negative and odd” if the number is negative and odd, “negative and even” if the number is negative and even, and “You picked 0” if the number is 0.

A possible anwer is:

int a;
Console.WriteLine("Enter an integer");
a = int.Parse(Console.ReadLine());
if (a >= 0)
{
    if (a % 2 == 0)
        Console.WriteLine("Positive and even");
    else // if (a % 2 != 0)
        Console.WriteLine("Positive and odd");
}
else
{
    if (a % 2 == 0)
        Console.WriteLine("Negative and even");
    else
        Console.WriteLine("Negative and odd");
}

That is a lot of repetition! We could actually construct “progressively” the message we will be displaying:

string msg;
if (a >= 0)
{
    msg = "Positive";
}
else
{
    msg = "Negative";
}
if (a % 2 == 0)
    msg += " and even";
else // if (a % 2 != 0)
    msg += " and odd";

Much better! Since the two conditions are actually independant, we can test them in two different if statements!

Switch Statements

switch statements allow to simplify the “matching” of a value against a pre-determined set of values. Its formal syntax is as follows:

switch (<variable name>)
{
    case (<literral 1>):
        <statement block 1>
        break;
    case (<literal 2>):
        <statement block 2>
        break;
    ...
    default:
        <statement block n>
        break;
}

The (…) are mandatory, the {…} are optional.

For instance, imagine we want to go from a month’s number to its name. We could do that with an if…else if …:

int month = 11;
string monthname;
if (month == 1) monthname = "January";
else if (month == 2) monthname = "February";
// ...
else if (month == 12) monthname = "December";
else monthname = "Error!";

But since we know that “month” will be a value between 1 and 12, or else we have an error, we could also have:

switch (month)
{
    case (1):
        monthname = "January";
        break;
    case (2):
        monthname = "February";
        break;
    // ..
    case (12):
        monthname = "December";
        break;
    default:
        monthname = "Error!";
        break;
}

Another example, to match a section letter against 4 possibilities, where two actually result in the same behaviour:

char section = 'c';
string meet;
switch (section)
{
    case ('a'):
        meet = "MW 1-2PM";
        break;
    case ('b'):
        meet = "TT 1-2PM";
        break;
    case ('c'):
    case ('d'):
 //   case ('a'): Would not compile!
        meet = "F 2-4PM";
        break;
    default:
        meet = "Invalid code";
        break;
}

Combining Methods and Decision Structures

Note that we can have a decision structure inside a method! If we were to re-visit the Rectangle class, we could have a constructor of the following type:

public Rectangle(int wP, int lP)
    {
        if (wP <= 0 || lP <= 0)
        {
            Console.WriteLine("Invalid Data, setting everything to 0");
            width = 0;
            length = 0;
        }
        else
        {
        width = wP;
        length = lP;
    }
}