Chapter 5 Key Takeaways: Making Decisions

The Big Picture

Programs become genuinely useful only when they can make decisions. This chapter introduced the two decision constructs in Pascal — if..then..else and case..of — along with the Boolean logic that drives them. Together with sequence (Chapter 3) and the upcoming loops (Chapter 6), decisions complete the trio of control structures that underlie all programming.


Ten Things to Remember

  1. IF..THEN executes a single statement conditionally. For multiple statements, wrap them in begin..end. Forgetting begin..end is one of the most common bugs in Pascal — only the first statement after then is conditional without it.

  2. No semicolon before ELSE. Pascal's semicolon is a statement separator, not a terminator. A semicolon before else ends the if statement, leaving else orphaned. This will cause a compiler error every time.

  3. The dangling else attaches to the nearest IF. When you nest if statements, else belongs to the innermost unmatched if. Use begin..end to override this when necessary.

  4. Always parenthesize Boolean subexpressions. Because and and or have higher precedence than =, <, and >, the expression x > 5 and y < 10 does not mean what you think. Write (x > 5) and (y < 10) instead.

  5. Short-circuit evaluation is your friend. Under {$B-} (the Free Pascal default), (x <> 0) and (100 div x > 5) is safe because the second condition is skipped when x equals zero. Use this pattern for guard conditions.

  6. The CASE statement requires ordinal types. You can use Integer, Char, Boolean, enumerations, and subranges — but not Real or String. The compiler builds a jump table for O(1) dispatch, which is why this restriction exists.

  7. Always include an ELSE clause in CASE. Defensive programming means handling unexpected values. Even when you believe your labels cover every possibility, the else clause catches the case you did not anticipate.

  8. Use named Boolean variables for complex conditions. Instead of cramming five conditions into one if, extract them into variables like isValidAmount and isValidCategory. The variable name documents your intent.

  9. Guard clauses flatten nested code. Validate early, exit early. This keeps your main logic at a shallow nesting depth, making the code easier to read and maintain.

  10. Test every branch, every boundary. For each decision, test inputs that make the condition true, false, and exactly at the boundary. This branch coverage is the minimum standard for testing conditional logic.


Quick Syntax Reference

{ Simple IF }
if condition then
  statement;

{ IF with block }
if condition then
begin
  statement1;
  statement2;
end;

{ IF..ELSE }
if condition then
  statementA
else
  statementB;

{ IF..ELSE IF chain }
if condition1 then
  statement1
else if condition2 then
  statement2
else
  defaultStatement;

{ CASE statement }
case selector of
  value1:       statement1;
  value2:       statement2;
  low..high:    rangeStatement;
  v1, v2, v3:  multiStatement;
else
  defaultStatement;
end;

{ Compound Boolean }
if (condA) and (condB) then ...
if (condA) or (condB) then ...
if not (condA) then ...

Common Mistakes Checklist

Before submitting any program with conditional logic, check for these errors:

  • [ ] No semicolon before else
  • [ ] begin..end used when multiple statements are conditional
  • [ ] All Boolean subexpressions are parenthesized
  • [ ] No comparison of Real values with = (use tolerance instead)
  • [ ] case selector is an ordinal type
  • [ ] Every case has an else/otherwise clause
  • [ ] No overlapping case labels
  • [ ] All branches tested with appropriate inputs
  • [ ] Boundary values explicitly tested

Connection to Themes

Theme 1 (Pascal Teaches Programming Right): Pascal's begin..end blocks, the := vs. = distinction, mandatory then keyword, and ordinal-only case selectors all eliminate categories of bugs that other languages silently permit. The language's design actively guides you toward correct decisions.

Theme 5 (Algorithms + Data Structures = Programs): The case statement's jump table demonstrates that data representation (ordinal types mapping to integers) determines algorithmic efficiency (O(1) dispatch vs. O(n) sequential checking). This principle will grow more powerful with arrays, records, and trees.