Concepts / Modular Programming with Functions

Modular Programming with Functions

The complete 3N+1 program uses the predefined function nextN() in a full program, showing how a function is put to work after it has been defined.

  • Programming

Starting From the Finished Program

This article closes the 3N+1 discussion with a complete program. Earlier in the chapter, the function nextN() was defined on its own. Here you see the same function put to work inside a full program that asks the user for starting values, computes several sequences, and reports results. Instead of starting from the definition of nextN(), this article starts from the finished program and asks what each piece is doing, so that the function's role becomes visible in the context where it is actually used.

Begin by reading the program as a whole before following any single line. The opening comment describes the program's purpose in plain language: it computes and displays several 3N+1 sequences, the starting values come from the user, the terms are printed in columns with five on each line, and the number of terms in each sequence is reported after the sequence is shown. That description is a map. Each part of the program you read later should fit somewhere on it.

The program also gets a presentation upgrade. Its terms are printed in neat columns, five to a line. That change looks cosmetic, but it introduces a second idea that matters just as much: the program keeps a running count of how many terms it has printed on the current line, and uses that count to decide when to move to a new line.

A Function That Hands Back a Value

A function that returns a value does its work and then hands a result back to whoever called it. The caller decides what to do with that result. It might store it in a variable, use it in a calculation, pass it to another function, or print it. Before tracing nextN() inside the larger program, it helps to test your expectations on a small function that has the same shape.

python
Output (expected)
10
Notes on the code
  • def double_it(x) defines the function; its body runs only when it is called
  • return 2 * x sends the computed value back to the caller
  • double_it(5) is the call; its result is stored in result

What do you think happens?

What does print(double_it(5) + 1) display?

  • 6

  • 10

  • 11

  • 16

Reveal answer
Answer:

11

The call double_it(5) is replaced by its returned value 10 once control comes back, so the expression becomes 10 + 1, which is 11.

Following Control Into and Out of nextN()

When the complete program needs the next term of a sequence, it calls nextN(). Control leaves the calling code, enters the function, and runs the function's body. When the function reaches its return, control goes back to the exact point where the call was made, and the returned value takes the place of the call in that expression.

Main programnextN()1. call nextN()2. return value to the call site
When main calls nextN(), where does execution jump to, and where does it return after the function finishes?

The main program is not finished when nextN() is called. It is paused at the call, waiting for an answer. The returned value is what allows the paused work to continue. This is why a function call can appear inside an assignment or a print statement: the call is replaced by its result once control returns.

Where the Returned Value Lands

A returned value must be received somewhere. The caller might assign it to a variable, as in result = double_it(5), or it might let the call sit inside a larger expression, as in print(double_it(5) + 1). In both cases, you can find the receiving point by locating the call in the source and reading the statement it belongs to. The receiving statement is where the value is used, and it is the place to inspect when a value looks wrong.

Worked example

Tracing a returned value through a statement

Given the generic function double_it from earlier, what value is stored in total after the statements total = double_it(3) + double_it(4)?

  1. 1
    Call double_it(3)

    Control enters the function with x equal to 3, computes 2 * 3, and returns 6. The call is replaced by 6.

  2. 2
    Call double_it(4)

    Control enters the function again with x equal to 4, computes 8, and returns 8. This call is also replaced by its result.

  3. 3
    Evaluate the sum

    The expression is now 6 + 8, which is 14.

  4. 4
    Receive the result

    The assignment stores 14 in the variable total.

Result

total holds 14

Counting Terms to Start a New Line

The column layout depends on one simple idea, which the source states directly: keep track of how many terms have been printed on the current line, and when that number reaches 5, start a new line of output. The program does not need to know anything about the sequence's values to do this. It needs only a count that goes up each time a term is printed and gets reset when a line is finished.

Print termAdd 1 to countcount equals 5?Start new line, resetcount to 0Next termyesno
On each pass through the loop, how does the counter change, and at which value does the program begin a new line of output?

To make the terms line up into neat columns, the program uses formatted output. Formatted output lets the program control how much space each printed value occupies, so that values in the same column start at the same position on each line. The source introduces this as the means of creating the neat columns, and the descriptive comment confirms the target of five terms per line.

Tracing a Count Through Seven Terms

python
Output (expected)
1 2 3 4 5 
6 7 
Notes on the code
  • count starts at 0 because no terms are printed yet
  • end=" " keeps the next value on the same line
  • count += 1 records each printed term
  • When count reaches 5, a new line begins and count is reset
count 1 after term 1count 2 after term 2count 3 after term 3count 4 after term 4count 5, line ends,reset to 0count 1 after term 6count 2 after term 7print termprint termprint termprint termprint termprint term
As the program runs, how does the count change after each term, and when does it return to zero?

Notice that the program never inspects the values 1 through 7 to decide where to break the line. The decision depends only on the count. Changing the printed values would not change where the line breaks, and a wrong count would move the breaks even if every value were correct.

Finding Where a Wrong Value First Appears

When a complete program produces an unexpected result, the most useful question is where the result first went wrong. Because this program combines a called function with a running count, there are two natural places to look: the value that comes back from the function call, and the count that decides line breaks. Trace each one from the moment it is produced to the moment it is used.

Debugging

Suppose a printed row has six terms when it should have five. Work backward from the bad row. First check the count: was it reset to 0 when the line ended, and was it incremented once per printed term? If the count is right, check the returned values: does each call return the term the program expects, and was that value stored or printed where you think it was? The first step where the recorded value differs from the value you expected is the step where the problem begins.

MEDIUM

A program prints a sequence and its count goes 1, 2, 3, 4, 5, then the line should break. Suppose the reset line is missing, so the count goes 1, 2, 3, 4, 5, 6, 7. At which term does the first incorrect line break happen, and what is the first wrong value in the count?

Hints
  • Compare the count after each term with the count the rule requires.
  • The first break that should occur is at count 5; check whether it happens.

Mistakes Beginners Make With Function Calls

  • Common mistake

    Expecting the function body to run in the middle of the caller without any return

    What it looks like

    Writing double_it(5) on a line by itself and then expecting the result to appear without storing or printing it

    Why it fails

    The call runs the function, but its returned value is only received if the caller uses it. Without an assignment or print, the value is discarded.

    Do this instead

    Write result = double_it(5) or print(double_it(5)) so the returned value has a place to go.

  • Common mistake

    Assuming the count resets on its own

    What it looks like

    Letting count keep rising past 5 and expecting a new line to start

    Why it fails

    The line break depends on the count reaching 5 and being reset. A count that is never reset cannot decide the next break correctly.

    Do this instead

    Reset the count to 0 each time a new line of output begins.

  • Common mistake

    Confusing the value a function returns with the value the caller stored before the call

Practice Tracing a Complete Run

EASY

Using the counting program above, change the range so it prints terms 1 through 12. Before running it, predict how many lines appear and how many terms are on the last line. Then check your prediction.

Hints
  • Five terms fit on each full line.
  • The count is reset after the fifth term of every line.
MEDIUM

Write a small function that returns twice its input, call it from a main section, and trace where the returned value is stored. Then add a count that starts a new line after every third value. Trace the count step by step and identify the first step where it would be wrong if you forgot to reset it.

Hints
  • Keep the function and the counting loop separate, so each one is easy to trace.
  • Write the count value on paper after each print.

Key Takeaways

  • A function that returns a value sends its result back to the caller, and the call is replaced by that result when control returns.
  • Control moves from the main program into nextN(), runs the function body, and comes back to the exact point of the call, where the returned value is used.
  • A running count of terms printed on the current line can decide when to start a new line; the count goes up with each term and is reset when a line finishes.
  • When a result is wrong, trace each returned value and the count from the step where they are produced to the step where they are used, and find the first step where the value differs from what you expected.