CSC108H1/Unit 2
Unit 2 · Intro to Programming

Control Flow

So far every program has run top to bottom. Control flow lets it choose and repeat, which is where programs stop being calculators and start being algorithms — and where indentation stops being cosmetic and starts being syntax.

By the end you can
  • Write correct if/elif/else chains.
  • Choose between for and while deliberately.
  • Trace nested loops and predict the output.
  • Diagnose an infinite loop and an off-by-one error.
Why it matters & where it comes from
Why it exists

A fixed sequence of steps can only ever do one thing. Branching and repetition are what let a fixed-length program handle inputs of any size, which is the whole idea of an algorithm.

In the real world

Every retry policy, every rate limiter, every game loop is control flow. The 2012 Knight Capital loss of $440 million in 45 minutes was a stale branch condition sending orders nobody intended.

Story & open questions

Dijkstra's 1968 letter "Go To Statement Considered Harmful" argued that unrestricted jumps make programs impossible to reason about. Python has no goto at all, which is that argument having won.

Conditionals

Definition

An if statement runs its block when the condition is truthy. elif chains additional tests; else catches everything remaining. At most one branch of a chain ever runs.

Example Order matters in a chain
python
def grade(mark: int) -> str:
    """Return the letter grade for mark."""
    if mark >= 80:
        return 'A'
    elif mark >= 70:
        return 'B'
    elif mark >= 60:
        return 'C'
    else:
        return 'F'
Because the chain stops at the first true test, a mark of 85 returns 'A' and never reaches the 70 test.
Reverse the order and it breaks: with >= 60 first, every passing mark returns 'C'. Chains must go from most to least restrictive.
Separate ifs are not a chain

Replacing elif with if makes each test run independently. With return inside, the behaviour happens to match; without it, several branches execute and the last one wins. Use elif when the cases are meant to be exclusive.

Rule Truthiness

Python treats as false: False, None, 0, 0.0, '', [], {}. Everything else is true. So if items: reads as "if the list is non-empty", which is the idiomatic emptiness test — prefer it to if len(items) > 0:.

Loops

Rule Which loop to reach for
for when you know what you are iterating over — a list, a string, a range. This is the default in Python.
while when you are waiting for a condition and cannot say in advance how many rounds it takes.

If you find yourself writing while i < len(xs) with a manual counter, you wanted a for.

Example The same sum, three ways
python
# idiomatic: iterate the values
total = 0
for x in nums:
    total = total + x

# by index, when you need the position too
for i in range(len(nums)):
    total = total + nums[i]

# both at once
for i, x in enumerate(nums):
    print(i, x)

Reach for the first form unless the index is genuinely needed. Marks in this course go to the version that says what it means.

Example range has three forms
python
range(5)        # 0 1 2 3 4      - stop only
range(2, 5)     # 2 3 4          - start, stop
range(2, 11, 3) # 2 5 8          - start, stop, step
range(5, 0, -1) # 5 4 3 2 1      - counting down

The stop value is always excluded. That single convention is behind most off-by-one errors, and it is also why range(len(xs)) gives exactly the valid indices.

Example Nested loops
python
for i in range(3):
    for j in range(2):
        print(i, j)
The inner loop runs completely for each single step of the outer, giving six lines: 0 0, 0 1, 1 0, 1 1, 2 0, 2 1.
Total work is the product, not the sum. Two nested loops over $n$ items do $n^2$ steps — the first hint of Unit 9's complexity.

break, continue, and the loop that will not end

Definition

break exits the innermost loop immediately. continue skips to the next iteration. Both apply only to the loop directly containing them.

Example Early exit
python
def first_negative(nums: list) -> int:
    """Return the first negative value in nums, or 0 if there is none."""
    for x in nums:
        if x < 0:
            return x
    return 0

Returning from inside the loop is cleaner than break plus a flag variable. Once the answer is known, leave.

Three ways to loop forever

• Nothing in the body changes the condition.
• The change moves the wrong way, so the condition never becomes false.
• The condition tests a float for exact equality, and floating point steps past it — see Unit 10.

If a program hangs, interrupt it and read which line it stopped on. That is almost always inside the offending loop.

Common pitfalls

• Mixing tabs and spaces. Python counts indentation as syntax; set the editor to spaces only.
• Forgetting the colon after if, for, while, def.
• Modifying a list while iterating over it. Items get skipped; iterate a copy with for x in xs[:] or build a new list.
• Comparing with and/or incorrectly: if x == 1 or 2: is always true, because 2 is truthy. Write if x == 1 or x == 2: or if x in (1, 2):.

Practice

Predict each answer before running it. Original exercises written for this guide in the style of the course's weekly sets.

Practice 1 · Count the lines

How many lines does for i in range(2, 10, 3) print?

Answer
Three: 2, 5, 8. The next would be 11, past the excluded stop.
Practice 2 · Chain order

What does grade(85) return if the chain tests >= 60 first?

Answer
'C'. The first true test wins, so a loose test placed early swallows everything above it.
Practice 3 · Trace nested

How many times does the inner body run?

python
for i in range(4):
    for j in range(i):
        print(i, j)
Answer
Six: $0+1+2+3$. The inner range depends on i, so the count is a triangular number rather than a product.
Practice 4 · Write it

Write a function returning True if a list is sorted ascending.

Solution
python
def is_sorted(xs: list) -> bool:
    """Return whether xs is in non-decreasing order.

    >>> is_sorted([1, 2, 2, 5])
    True
    """
    for i in range(len(xs) - 1):
        if xs[i] > xs[i + 1]:
            return False
    return True
Note len(xs) - 1: comparing each item to its successor means stopping one early. An empty or one-item list correctly returns True.
Practice 5 · Infinite loop

Why does this never end, and what is the fix?

python
n = 10
while n != 0:
    n = n - 3
Answer
n takes values 10, 7, 4, 1, -2, ... and skips 0 entirely. Test while n > 0: instead. Prefer inequality to equality when stepping by anything other than one.
Practice 6 · Mutation during iteration

What goes wrong here?

python
for x in xs:
    if x < 0:
        xs.remove(x)
Answer
Removing shifts every later item down one while the loop's internal index keeps advancing, so items get skipped. With [-1, -2, 3] the -2 survives. Build a new list: xs = [x for x in xs if x >= 0].
Practice 7 · while versus for

Which loop suits reading input until the user types quit?

Answer
while. The number of rounds is unknown in advance, which is exactly the case while exists for.
Practice 8 · FizzBuzz

Print 1 to 15, replacing multiples of 3 with Fizz, of 5 with Buzz, of both with FizzBuzz.

Solution
python
for n in range(1, 16):
    if n % 15 == 0:
        print('FizzBuzz')
    elif n % 3 == 0:
        print('Fizz')
    elif n % 5 == 0:
        print('Buzz')
    else:
        print(n)
Testing % 15 first is the whole trick: the most restrictive case has to come before the cases it also satisfies.

Expanded topic checklist

Course coverage. This unit is part of the complete CSC108H1 topic map. It should cover the following items before you move on:

  • Conditionals. if/elif/else, chain ordering, and truthiness.
  • Loops. for over a sequence, while on a condition, and when each is right.
  • range. All three forms and the excluded stop.
  • Loop control. break, continue, early return, and diagnosing infinite loops.
Textbook/source alignment

The calendar lists "program structure: control flow" immediately after the elementary types. Check the syllabus on Quercus for the week this lands and for the assigned exercises.

Core idea map

Conditions choose; loops repeat; both are delimited by indentation. Unit 3 wraps these in functions so they can be named, tested and reused.

Study routine. Trace every loop on paper with a small input before running it. Predicting output is a tested skill, and tracing is the only way to build it.

Deep practice extensions

Use these after the main practice set. They push on definitions and edge cases rather than routine calculation.

Extension 1 · Chain semantics

How many branches of an if/elif/else chain run?

Guide
Exactly one, the first whose test is true, or the else if none is.
Extension 2 · Excluded stop

Why does range(len(xs)) give valid indices?

Guide
Because the stop is excluded, it yields $0$ through $n-1$ — exactly the legal positions of an $n$-item list.
Extension 3 · Loop choice

When is while the right choice?

Guide
When the number of iterations is not known ahead of time and depends on a condition re-evaluated each round.
Extension 4 · Nested cost

Two nested loops over $n$ items do how many iterations?

Guide
$n^2$. Nesting multiplies, and that is where quadratic running time comes from.