Concepts / Writing Loops Inside Subroutines

Writing Loops Inside Subroutines

A parameterized subroutine declares a parameter list in its definition, which specifies the number and types of values a caller must supply.

  • Programming

A Subroutine You Can Run

This article starts with a subroutine rather than a list of rules. The subroutine prints a 3N+1 sequence. The number the sequence starts from is not written inside the subroutine. Instead, the caller supplies that number each time it calls the subroutine. As you read, keep one question in mind: when the subroutine runs, where does its starting number come from, and at what point does it first have a value?

What do you think happens?

Inside the subroutine, where does the starting number come from?

  • It is written inside the subroutine body

  • The caller supplies it in the call statement

  • It is stored in a file the subroutine reads

Reveal answer
Answer:

The caller supplies it in the call statement

The subroutine's definition declares a parameter but does not give it a value. The number the subroutine starts from is the value the caller places inside the parentheses of the call.

Why Subroutines Get Called More Than Once

Imagine a program that needs the same job done in three different places. You could copy the same lines of code three times, or you could write those lines once and let the rest of the program use them whenever they are needed. A subroutine is the second option. It is a block of code that can be called multiple times from different parts of a program.

The important word is called. A subroutine does not run just because it exists in a program. It runs when the program reaches a point where it calls it. Because the same block can be called more than once, a single piece of code can serve many moments in a single run of the program.

Reading a Parameter List

The subroutine in this article is declared with a parameter list in its header. The header is static void print3NSequence(int startingValue). The part in parentheses is the parameter list. It says that the subroutine expects exactly one parameter, and that the parameter is of type int. The number and types of the parameters in this list tell any caller what must be supplied.

static voidkeywords before the nameprint3NSequencename the caller uses in acallinttype the caller's valuemust matchstartingValuename the body uses
Which parts of the header (keywords, name, parameter type, parameter name) tell the caller what values to supply, and in what order?

Read the header from left to right to find what a caller needs. The name tells the caller which subroutine to invoke. The type in the parameter list, int, tells the caller what kind of value must be supplied inside the parentheses. The parameter name, startingValue, is the name the body will use for that value. The caller does not need to know this name to make the call, because the value is passed in by position.

How a Call Value Reaches the Parameter

The definition does not give the parameter a value. The value comes from the call statement. When the computer executes a subroutine call statement, it first assigns the value supplied in the call to the parameter name, and only then executes the statements of the subroutine body. The parameter name can then be used inside the body in the same way as a variable name.

Callprint3NSequence(17)startingValueparameter receives 17Body first statementstartingValue already holds17assign 17body uses parameter
When the call print3NSequence(17) runs, where does the 17 go, and what does the parameter hold at the first line of the body?

The timing is the key point. The assignment to the parameter happens before the first statement of the body, which is why the body can rely on the parameter already holding a value. If you want to know what the body sees on its first line, the answer is always the value the call supplied.

Tracing a Call That Uses a Variable

Worked example

Tracing print3NSequence(K) step by step

Given the driver above, what value does the body use as its starting point when the second call runs?

  1. 1
    Read the caller's variable

    The call is print3NSequence(K). The computer takes the current value of K, which is 5.

  2. 2
    Assign to the parameter

    The value 5 is assigned to startingValue. The variable K is the source of the value; startingValue is the name the body uses.

  3. 3
    Run the body

    Only after the assignment does the body execute, and it prints the sequence beginning at 5.

Result

The body begins from 5, because the value of K was copied into startingValue before the first statement of the body ran.

What do you think happens?

Inside the body, can the code refer to the caller's name K directly?

  • Yes, the body can read K because it is a variable in the program

  • No, the body refers to the value through startingValue

Reveal answer
Answer:

No, the body refers to the value through startingValue

The body is written in terms of startingValue, so it has no direct connection to the name K in the caller. Any variable in the caller could be passed, as long as its current value is what the call should use.

Tracing Several Calls From the Main Program

A main program can call the same subroutine at several points in its run. Each call is a separate event. Control leaves the main program, enters the subroutine, runs the body with that call's value, and then returns to the point where the call was made. The sequence below uses the two calls from the driver plus one additional call with a different value to show the pattern.

Main programprint3NSequencecall with 17returncall with Kreturncall with 12return
When main calls the same subroutine at three different points, in what order does control jump, run the body, and return?

Notice that each call starts the body fresh with its own supplied value. The first call supplies 17, the second supplies the current value of K, and the third supplies 12. The same definition is used every time, and only the value assigned to startingValue changes between calls.

Finding Where a Wrong Result Begins

When a parameterized subroutine produces a wrong result, you can narrow down the cause by following one path in order. First, identify the value supplied by the call. Second, check its assignment to the parameter. Third, check the body's first use of that parameter. The step where the value first differs from what you expected is where the problem begins.

Supplied valuewhat the call passesstartingValueassignedvalue after assignmentBody first usefirst place the body readsitassignmentfirst statement
If the output is wrong, at which step did the parameter's value first differ from what was expected?

Subroutines in ThreeN2.java

The source points to ThreeN2.java as a concrete program that uses subroutines. It is introduced as an improved version of the 3N+1 program, and the source describes it as a program that uses subroutines and prints its output in neat columns. The source does not list the individual subroutines inside ThreeN2.java or show their code, so this article does not describe them in detail.

The source gives two reasons ThreeN2.java relies on subroutines. The first is code organization: separating work into named blocks makes the program easier to read and manage. The second is output formatting: the program prints its results in neat columns, and the subroutines are part of how that formatting is achieved. When you open the file yourself, look for the places where the program calls a named block of code, and compare them with the places where it prints results.

Mistakes Beginners Make With Parameters

  • Common mistake

    Thinking the parameter list gives the parameter a value

    What it looks like

    Reading the header static void print3NSequence(int startingValue) and assuming startingValue already holds a number.

    Why it fails

    The definition declares the parameter but does not give it a value. The value arrives from the call statement.

    Do this instead

    Look at the call statement to find the value, then follow it to the parameter.

  • Common mistake

    Expecting the body to use the caller's variable name

    What it looks like

    Assuming the body refers to K when the call is print3NSequence(K).

    Why it fails

    The body is written in terms of startingValue. The caller's variable is only the source of the value.

    Do this instead

    Track the current value of K at the moment of the call, then follow it into startingValue.

  • Common mistake

    Assuming a subroutine runs just because it is written

    What it looks like

    Writing the subroutine and expecting its output to appear without any call.

    Why it fails

    A subroutine runs when the program reaches a point where it calls it.

    Do this instead

    Find the call statement that names the subroutine to see when it runs.

  • Common mistake

    Forgetting that each call supplies its own value

Practice Tracing Calls

EASY

A program contains the header static void print3NSequence(int startingValue) and the driver lines int K = 8; print3NSequence(K); K = 3; print3NSequence(17);. For each call, state the value assigned to startingValue before the body runs. Then explain whether the second call uses 8 or 3 when the body executes its first line.

Hints
  • Find the value of K at the exact moment each call statement runs, not when the variable was first declared.
  • The body only sees startingValue, so ask what value was assigned to that parameter for each call.
MEDIUM

A driver calls print3NSequence(K) three times, and the second call prints a sequence that starts from an unexpected number. Describe the three steps you would check, in order, to locate the step where the value first diverges.

Hints
  • Start with the value supplied by the call.
  • Then check the assignment to startingValue and the body's first use of it.

Key Takeaways

  • A parameterized subroutine declares a parameter list in its definition, which tells a caller how many values to supply and of what types.
  • The definition does not give the parameter a value; the call statement supplies it, and the assignment happens before the body's first statement runs.
  • A subroutine runs only when a call statement reaches it, so one named block can serve many points in a single program run, each with its own supplied value.
  • When a result is wrong, trace the supplied value, its assignment to the parameter, and the body's first use of it, in that order, to find the step where the value first diverges.
  • ThreeN2.java uses subroutines to organize its code and to help format its output in neat columns.