5.3. if-else Statements

Run the example program, clothes/clothes.cs. Try it at least twice, with inputs 50 and then 80. As you can see, you get different results, depending on the input. The main code of clothes/clothes.cs is:

1
2
3
4
5
6
7
8
double temperature = UIF.PromptDouble("What is the temperature? ");
if (temperature > 70) {
   Console.WriteLine("Wear shorts.");
}
else {
   Console.WriteLine("Wear long pants.");
}
Console.WriteLine("Get some exercise outside.");

The lines labeled 2-7 are an if-else statement. Again it is close to English, though you might say “otherwise” instead of “else” (but else is shorter!). There are two indented statements in braces: One, like in the simple if statement, comes right after the if condition and is executed when the condition is true. In the if-else form this is followed by an else (lined up under the if by convention), followed by another indented statement enclosed in braces that is only executed when the original condition is false. In an if-else statement exactly one of two possible parts in braces is executed.

A final line is also shown that is not indented, about getting exercise. The if and else clauses each only embed a single (possibly compound) statement as option, so the last statement is not part of the if-else statement. It is beyond the if-else statement; it is just a part of the normal sequential flow of statements. We repeat:

Note

Inside an if-else there is a choice made of which clause to execute and which clause to skip, but the whole if-else construction is a single larger statement, which exists in the normal sequential flow of execution.

The compiler does not require the indentation of the if-true-statement and the if-false-statement, but it is a standard style convention.

The general C# if-else syntax is

if ( condition ) {
statement(s) for if-true
}
else {
statement(s) for if-false
}

The statements chosen based on the condition can be any kind of statement. This is the suggested form, but as with the plain if statement, the if-true compound statement or the if-false compound statement can be replace by a single statement without braces, except in one otherwise ambiguous situation later, Match Wrong if With else.

5.3.1. Scope With Compound Statements

The section Local Scope referred to function bodies, which happen to be enclosed in braces, making the function body a compound statement. In fact variables declared inside any compound statement have their scope restricted to inside that compound statement.

As a result the following code makes no sense:

static int BadBlockScope(int x)
{
   if ( x < 100) {
      int val = x + 2;
   }
   else {
      int val = x - 2:
   }
   return val;
}

The if-else statement is legal, but useless, because whichever compound statement gets executed, val ceases being defined after the closing brace of its compound statement, so the val in the return statement has not been declared or given a value. The code would generate a compiler error.

If we want val be used inside the braces and to make sense past the end of the compound statement, it cannot be declared inside the braces. Instead it must be declared before the compound statements that are parts of the if-else statement. A local variable in a function declared before a nested compound statement is still visible (in scope) inside that compound statement. The following would work:

static int OkScope(int x)
{
   int val;
   if (x < 100) {
      val = x + 2;
   }
   else {
      val = x - 2;
   }
   return val;
}

There is even more subtlety here than meets the eye: An if-else statement can generally be rewritten as two simple if statements (though it is less efficient and less clear). The two if statements would use opposite conditions, as in this variation:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
static int OkScope2(int x)
{
   // without the = 0: Unassigned local variable error
   int val = 0;
   if (x < 100) {
      val = x + 2;
   }
   if (x >= 100) {
      val = x - 2;
   }
   return val;
}

Note that in this variation we added an initialization for val to be 0, though the value of the initialization is never used: val is guaranteed to be assigned a value in one of the if statements before its value is used in the return statement.

Open Xamarin Studio with the examples solution, and open ok_if_scope/ok_if_scope.cs in the edit window. The last function, OkScope2, is the one shown above. Now remove the logically unnecessary = 0 initialization for val so the line is just int val;. As the comment says, an error should appear (at least after you try to compile the program). The error will say that there is an uninitialized local variable! Why?

For safety the C# compiler has some basic analysis to check that every local variable gets given a value before its value is used. In the OkScope function there is no one place where val gets an initial value, but the compiler is smart enough to see that one of the branches of any if-else statement is always taken, and val gets a value in each, so there is no problem.

The compiler analysis is not complete: It does not actually evaluate any expressions. This is good enough to catch many initialization errors that coders make, but it is not sufficient in general: We can see this from the altered OkScope2.

The original code shows the fix: Give a dummy initialization that is never used in execution, but keeps the compiler happy.

Although this extra initialization is annoying, the extra step is rarely needed. Meanwhile it is very easy to forget to give a value to a local variable before use! Having the error caught quickly by the compiler is very handy, offsetting the extra work when the compiler gives this error unnecessarily.

5.3.2. If-else Exercise

Think of two different inputs you could give that would make the execution of the code fragment proceed differently. What would happen in each case? (Assume we have access to the class UIF.)

  1. Consider:

    string v = UIF.PromptLine("Enter a word: ");
    if (v.Length > 3) {
       v = v + v;
       Console.WriteLine("Now we have " + v);
    }
    else {
       Console.WriteLine("We still have " + v);
    }
    
  2. Consider:

    int x = UIF.PromptInt("Enter a integer: ");
    Console.Write("The magnitude of " + x + " is ");
    if (x < 0) {
       Console.WriteLine(-x);
    }
    else {
       Console.WriteLine(x);
    }