Concepts / Writing Your First Subroutine

Writing Your First Subroutine

A parameter is a value passed to a subroutine so that one fixed procedure can handle different inputs.

  • Programming

Why a Fixed Procedure Needs Varying Input

Many programming tasks are the same from one run to the next, but the details change each time. Printing a list of numbers is a good example. The act of printing never changes, yet which numbers appear depends on the situation. A subroutine that performs such a task would be wasteful if it had to be rewritten for every variation of the numbers. Instead, we give it a way to receive the details it needs at the moment it is called.

The mechanism for doing this is the parameter. A parameter is a value passed to a subroutine so that one fixed procedure can handle different inputs. In this article we introduce parameters through a problem we have already met: the 3N+1 sequence. Before you see any code, try to hold two questions in mind. What part of the job stays the same every time the subroutine runs? What part could be different on each call?

Recalling the 3N+1 Rule

The 3N+1 sequence is generated by a rule that begins with a number N. If N is odd, it is replaced with three times N plus one. If N is even, it is replaced with N divided by two. The step is applied again and again until N becomes 1.

Rule

Worked example

Generating the sequence from a starting value of 3

Apply the 3N+1 rule starting from N equal to 3 and list every value produced until N reaches 1.

  1. 1
    Start

    N is 3, which is odd, so the next value is 3 times 3 plus 1, which is 10.

  2. 2
    Second step

    N is 10, which is even, so the next value is 10 divided by 2, which is 5.

  3. 3
    Third step

    N is 5, which is odd, so the next value is 3 times 5 plus 1, which is 16.

  4. 4
    Remaining steps

    From 16 the values are 8, 4, 2, and finally 1, where the process stops.

Result

The full sequence is 3, 10, 5, 16, 8, 4, 2, 1.

Tracing a Starting Value Through the Subroutine

Now imagine the job we want a subroutine to do: print out a 3N+1 sequence. The job itself is fixed. The subroutine always prints a 3N+1 sequence, and it always follows the same rule. What changes from call to call is the number the sequence begins with. The caller decides which starting value to use and hands it over. The subroutine receives that value under a name of its own, which is the parameter, and uses it to carry out the fixed procedure.

Callercalls print_sequence(3)Parameter nholds 3 on entry3N+1 ruleodd or even testPrinted sequence3 10 5 16 8 4 2 1passes 3applies to nrepeats until 1
When the caller supplies 3, where does that value go inside the subroutine, and how does it become the printed result?

Read the diagram from left to right. The caller supplies a value. That value enters the subroutine as the parameter n. The fixed rule then runs on whatever n holds, and the printed sequence is the result. The number 3 determines where the chain of values begins, and the rule determines everything after that.

What do you think happens?

Suppose the caller passes 6 instead of 3. Before reading on, predict the first value that gets printed and the full list.

Reveal answer
Answer:

The printed list is 6, 3, 10, 5, 16, 8, 4, 2, 1.

The subroutine prints the starting value first. Since 6 is even, the next value is 6 divided by 2, which is 3. From 3 the rule continues exactly as it did in the earlier example, producing 10, 5, 16, 8, 4, 2, 1.

The Parameter as a Named Entry Point

A subroutine's header names its parameter, and the body refers to that name. Whatever value the caller passes is what the name holds when the subroutine runs. The sketch below is an illustration written for this article. It is not the listing from the source textbook, which does not reproduce the subroutine code in the passage we are working from. It shows the idea in Python: the header names a parameter called n, and the body applies the 3N+1 rule to whatever value that name holds.

Code walkthrough
def print_sequence(n):
    while n != 1:
        print(n)
        if n % 2 == 1:
            n = 3 * n + 1
        else:
            n = n // 2
    print(n)

print_sequence(3)
  1. 1
    def print_sequence(n): declares the subroutine and names its single parameter n.
  2. 2
    while n != 1: repeats the body until the current value reaches 1.
  3. 3
    print(n) outputs the current value before it is changed.
  4. 4
    if n % 2 == 1 tests whether n is odd; the branch then applies three times n plus one, or else halves n.
  5. 5
    print(n) after the loop displays the final 1.
  6. 6
    print_sequence(3) is the call: the caller passes 3, which the subroutine receives as n.
  • The name n in the header is the parameter that receives the caller's value.
  • The while loop applies the fixed 3N+1 rule and stops when n reaches 1.
  • The final print displays the 1 that ends the sequence.
Output
3
10
5
16
8
4
2
1
Output
3
10
5
16
8
4
2
1

Same Procedure, Different Results

Two calls with different starting values produce two different printed lists, even though the procedure that produces them is identical. The diagram below places the two calls side by side. Both columns use the same subroutine body. Only the starting value differs.

Starting value 3Printed sequence3 10 5 16 8 4 2 1Starting value 6Printed sequence6 3 10 5 16 8 4 2 1same rulesame rule
If the same subroutine is called with 3 and then with 6, how do the two printed outputs differ, and what stays identical?

The two lists differ only at the start. The call with 6 prints 6 first, then continues into the same run of values that the call with 3 reaches after its first step. The body of the subroutine did not change between the two calls. The starting value arriving at the parameter did.

Mistakes Beginners Make with Parameters

  • Common mistake

    Rewriting the subroutine body for each new starting value

    What it looks like

    Writing one routine that prints the sequence for 3, another for 6, and another for 5.

    Why it fails

    The task is the same each time. Only the starting value varies, so separate copies duplicate the same rule.

    Do this instead

    Write one subroutine with a parameter, and let each caller pass the value it needs.

  • Common mistake

    Assuming the parameter is the caller's variable

    What it looks like

    Expecting the subroutine to change a variable named start in the caller just because the parameter is named n inside the subroutine.

    Why it fails

    The subroutine receives the value under a name of its own. The name n is local to the subroutine.

    Do this instead

    Think of the parameter as receiving a value, and use the caller's variables only as the source of that value.

  • Common mistake

    Treating the fixed rule as something the caller supplies

    Why it fails

    The caller supplies the varying input. The procedure, here the 3N+1 rule, stays inside the subroutine.

Practice Tracing a New Call

EASY

Using the print_sequence subroutine described in this article, trace the output of the call print_sequence(5). Write each value that gets printed, in order.

Hints
  • The subroutine prints the starting value first.
  • Check whether 5 is odd or even, then apply the matching step.
  • Keep applying the rule until the value becomes 1, then remember that the final 1 is printed too.

Key Takeaways

  • A parameter is a value passed to a subroutine so that one fixed procedure can handle different inputs.
  • The caller supplies the varying starting value, and the subroutine receives it under its own parameter name.
  • In the 3N+1 example, the printing task and the rule stay the same while the starting value changes from call to call.
  • Parameters let one subroutine produce many different results without rewriting its body.