.. highlight:: c++
  :linenothreshold: 5

************
Control Flow
************
Control flow, a.k.a. flow of control, is the order of the instruction execution
in an imperative program.

Types
=====
+ Sequential

  The fundamental control flow is the execution of instructions one after
  another in the natural order of the instructions.

+ Branch/Selection/Conditional

  Execution of different sets of instructions according to a condition.

+ Loop/Iteration

  Repeated executions of a sequence of instructions according to a condition

Branch
======
Branch Statements
-----------------
+ if-else

  * boolean expression
  * optional else
  * **optional {} when only one statement in its body**
  * if, else pairing
  * negating logic to swap if and else blocks

+ switch

  * expression types: int, char, etc.
  * mandatory {}
  * default case
  * use of break statements
  * merged cases

+ break

Branch Pitfalls
---------------
+ switch on double/float values
+ missing break statements in switch
+ bad boolean expression in if
+ incorrect use of {}

::

  // ==== branch ====

  // ---- correct ----
  if (a > 10) cout << "a is greater than 10\n";

  if (a > 10)
    cout << "a is greater than 10\n";

  if (a > 10) {
    cout << "a is greater than 10\n";
  }

  // ---- wrong ----

  // empty if, will run but the if block is empty
  // the second line is not part of the if and will run always
  if (a > 10);
    cout << "a is greater than 10\n";

  // missed {} so the third line is not part of the if and will run always
  if (a > 10)
    cout << "a is greater than 10\n";
    cout << "Please try a smaller value!\n";

  // will run but does not mean a is between 1 and 10
  if (1 < a < 10)
    cout << "a is between 1 and 10\n";

  // switch on double
  // double value is not exact
  // this snippet may work and may cause problem
  double a;
  cin << a;
  switch (a) {
    case 1.0:
      ...
      break;
    case 2.0:
      ...
      break;
    ...
  }

  // missing break
  // will also display "case 2" when input is 1
  switch (input) {
    case 1:
      cout << "Case 1" << endl;
    case 2:
      cout << "Case 2" << endl;
    // ...
  }

  // ---- poor ----

  bool flag;
  // calculate flag
  if (flag == true)  // should be if (flag)
    cout << "True\n";

Branch Patterns
---------------
Various ways to solve the same grade conversion problem are compared below.

+ Multi-way branching

  * switch (not always work, depend on math tricks)
  * if-else if-...-else
  * nested if-else
  * standalone if-else

  ::

    // switch version
    // use integer division
    // not a general solution
    // why no break statements are needed here?
    char percentToLetterGrade1(int percentGrade) {
      switch (percentGrade / 10) {
        case 10:
        case 9:
          return 'A';
        case 8:
          return 'B';
        case 7:
          return 'C';
        case 6:
          return 'D';
        default:
          return 'F';
      }
    }

    // nested if-else version
    // implicit conditions
    // least comparison in the worst case
    char percentToLetterGrade2(int percentGrade) {
      if (percentGrade >= 70)
        if (percentGrade >= 90)
          return 'A';
        else if (percentGrade >= 80)
          return 'B';
        else
          return 'C';
      else if (percentGrade >= 60)
        return 'D';
      else
        return 'F';
    }

    // flat if-else version
    // nested only in else block
    // implicit conditions
    // most readable
    char percentToLetterGrade3(int percentGrade) {
      if (percentGrade >= 90)
        return 'A';
      else if (percentGrade >= 80)
        return 'B';
      else if (percentGrade >= 70)
        return 'C';
      else if (percentGrade >= 60)
        return 'D';
      else
        return 'F';
    }

    // flat if version
    // no implicit condition
    // also most readable
    // more comparisons
    char percentToLetterGrade4(int percentGrade) {
      if (percentGrade >= 90)
        return 'A';
      if (percentGrade < 90 && percentGrade >= 80)
        return 'B';
      if (percentGrade < 80 && percentGrade >= 70)
        return 'C';
      if (percentGrade < 70 && percentGrade >= 60)
        return 'D';
      if (percentGrade < 60)
        return 'F';
    }

Loop
====
Loop Statements
---------------
+ while

  * boolean expression
  * **optional {} when only one statement in its body**

+ do-while

  * boolean expression
  * **optional {} when only one statement in its body**
  * at least run once
  * not general

+ for

  * initialization; boolean expression; update
  * **optional {} when only one statement in its body**
  * translate to the equivalent while loop

+ break
+ continue

Break, Continue and Return
--------------------------
Modify the flow of control in a loop

:break: jump out of the inner most loop
:continue: jump to the start of the next round in the loop
:return: jump out of the function

Loop Pitfalls
-------------
+ bad initial value
+ exit conditions are not checked right after they are changed

  ::

    // wrong! The last negative input as the terminator
    // will be added to the sum
    int input = -1;
    int sum = 0;  // do not forget to initialization to 0
    while (input > 0) {  // where the condition is checked
      cout << "Please input a positive value to sum up (negative value to exit): ";
      cin >> input;  // where the condition changed!
      sum += input;  // where the mistake happens
    }

    // correct way
    int input;
    int sum = 0;
    while (true) {
      cout << "Please input a positive value to sum up (negative value to exit): ";
      cin >> input;  // where the condition changed!
      if (input < 0)
        break;  // where the condition is checked
      sum += input;
    }

+ bad border conditions

  * check first run
  * check last run

  ::

    // expect print 0 to 5
    for (int i = 0; i < 5; ++i)  // last round wrong should be i <= 5 or i < 6
      cout << i << " ";

    // expect to get a positive integer
    int input;
    while (input < 0) {  // first round wrong! input has no initial value!
      cout << "Please input a positive value (negative value to exit): ";
      cin >> input;
    }

+ variable scope problem

  ::

    for (int i = 0; i < 5; ++i)
      cout << i << " ";
    cout << i;  // wrong! variable i is out of scope

Loop Patterns
-------------
Check the `chapter 2 examples`_.

* input validation
* input validation with error message
* text menu operation
* statistical analysis

.. _chapter 2 examples: https://github.com/uwf-fang/cop3014-examples/tree/master/ch02-variable-control-flow