Concepts / Parameters and Arguments in Subroutines

Parameters and Arguments in Subroutines

Modifiers appear at the front of a subroutine definition and set characteristics such as whether it is static or public.

  • Programming

Why Programmers Read the Header First

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: a block of code that can be called multiple times from different parts of a program.

What do you think happens?

If a program needs the same calculation in several places, where would you rather keep the instructions for it: in one place, or in every place it is needed?

Reveal answer
Answer:

In one place. A subroutine lets the program write the instructions once and reuse them at every point where they are needed.

Copying the same lines into several places means every copy must be kept up to date. A single subroutine holds the instructions in one spot, and each call reuses them.

The rest of this article follows the way a reader meets a subroutine. Programmers who call a subroutine rarely read its body first. They read the header, because the header describes how the subroutine can be used: what it is, what it hands back, and what it needs to be given. Think of the header as a short contract between the subroutine and anyone who calls it.

Tracing Control Through Repeated Calls

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. The word called is the important one.

Consider a small generated example. A subroutine named printRow prints one line of output. The main program calls printRow at two different points, once with the value 3 and once with the value 7. The diagram shows the path control takes: main pauses at each call site, control jumps into printRow, the subroutine finishes, and control returns to the line in main that follows the call.

maincalling codeprintRowsubroutinecall 1 with 3return to line after call 1call 2 with 7return to line after call 2
When main calls printRow at two points, where does execution jump to, and where does it resume after printRow finishes?
Worked example

Tracing the printRow program

main calls printRow(3), then does one more line of work, then calls printRow(7). What is printed, and in what order?

  1. 1
    Step 1

    main reaches the first call. Execution jumps into printRow, and its parameter n receives the value 3.

  2. 2
    Step 2

    printRow prints 3 and finishes. Control returns to the line in main directly after the first call.

  3. 3
    Step 3

    main runs its next line, then reaches the second call. Execution jumps into printRow again, this time with n holding 7.

  4. 4
    Step 4

    printRow prints 7 and finishes. Control returns to main, which continues with the lines after the second call.

Result

The output is 3 then 7. One block of code produced two outputs because it was called twice.

Reading a Subroutine Header

Every subroutine begins with a header line that comes before the braces and the code inside them. The header reads from left to right: modifiers at the front, then the return type, then the subroutine's name, then the parameter list in parentheses. For each piece, the question to keep in mind is the same: what does this part promise or require when someone uses the subroutine?

publicmodifierstaticmodifierdoublereturn typecomputeAreaname(double width, doubleheight)parameter list
Which token is the modifier, which is the return type, which is the name, and which declares the parameters?

Put the parts together and the header is a compact summary of how the subroutine is used. The modifiers tell you about its characteristics, the return type tells you what comes back, the name identifies the block, and the parameter list tells you what must be supplied when you call it. The header therefore answers several questions before you read a single line of the body.

Declaring Multiple Parameters Correctly

When a parameter list holds more than one parameter, each parameter needs its own type. The correct form for two double values is double x, double y. Writing double x, y is incorrect, because y then has no type of its own. The parameters are separated by commas, and each one is read as a pair of type and name.

java
Output
3
7
Notes on the code
  • computeArea is a function: its return type is double, so it hands a value back to the caller
  • printRow is a void subroutine: nothing comes back, so the call only prints
  • Each parameter in computeArea has its own type: double width, double height
  • main calls printRow twice, which is why its output appears twice in the run
3.0first argumentwidthfirst parameter, typedouble4.5second argumentheightsecond parameter, typedoubleposition 1position 2
In the call computeArea(3.0, 4.5), which argument goes into which parameter, and what does the order of the list control?

In the call computeArea(3.0, 4.5), the first argument fills the first parameter, width, and the second fills height. The parameter list is therefore a contract about order as well as type. If a caller swapped the arguments to computeArea(4.5, 3.0), the subroutine would still receive two values of the right type, but width would now hold 4.5 and height would hold 3.0. The program would run, but the meaning of the inputs would be reversed.

Mistakes When Writing Parameter Lists

  • Common mistake

    Giving only the first parameter a type

    What it looks like

    double x, y

    Why it fails

    Each parameter needs its own type. The declaration gives x a type, but y has no type of its own.

    Do this instead

    double x, double y

  • Common mistake

    Treating a void subroutine as if it returns a value

    What it looks like
    int total = printRow(3);
    Why it fails

    A subroutine whose return type is void hands nothing back, so there is no value to store.

    Do this instead

    Call printRow(3); on its own line, and use a function with a non-void return type if you need a result.

  • Common mistake

    Assuming a modifier decides what the parameters are

    What it looks like

    Reading static in the header and expecting it to say what input is accepted

    Why it fails

    Modifiers set characteristics such as static or public. The accepted inputs are declared in the parameter list.

    Do this instead

    Read the parameter list in the parentheses to learn what the subroutine needs.

  • Common mistake

    Passing arguments in the wrong order

    What it looks like
    computeArea(4.5, 3.0) when the intended width is 3.0
    Why it fails

    Arguments are matched to parameters by position, so the first value always goes to the first parameter.

    Do this instead

    Line up each argument with the parameter it is meant to fill, in the same order as the list.

  • Common mistake

    Forgetting that a subroutine runs only when it is called

Where ThreeN2.java Uses Subroutines

The source material points to a concrete program that uses subroutines: ThreeN2.java. It is introduced in Section 4.4 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 section does not describe them in detail.

What the source does establish is the reason the program uses subroutines. The first reason is code organization: separating work into named blocks makes the program easier to read and manage. The second reason is output formatting: the program prints its results in neat columns, and the subroutines are part of how that formatting is achieved.

MEDIUM

Open ThreeN2.java and find the places where the program calls a named block of code. Compare them with the places where it prints results. For each call you find, note whether the subroutine it reaches is doing computation or formatting output.

Hints
  • Look for a method name followed by parentheses where the program is not defining it.
  • Output in neat columns is usually produced by the code that prints, so compare the print statements with the calls around them.

Practice: Reading a Header and Tracing Calls

MEDIUM

Here is a header: public static void showTotal(int count, double price). Without reading any body, state three things a caller can tell from this header: whether a value comes back, how many inputs are required and of which types, and what the modifiers promise. Then write a main method that calls showTotal twice, with two different sets of arguments, and state where execution resumes after each call.

Hints
  • The return type is the word after the modifiers and before the name.
  • The parameter list is inside the parentheses, and each parameter has its own type.

Key Takeaways

  • A subroutine is a block of code that runs when a program calls it, and the same block can be called many times from different parts of a program.
  • The header reads left to right: modifiers set characteristics such as static or public, the return type says what comes back, and the parameter list declares what must be supplied.
  • A function's return type names the value it hands back, while a void subroutine returns nothing and is called for its effect.
  • Each parameter in a list needs its own type and name, written as type followed by parameter name, and arguments fill parameters by position.
  • ThreeN2.java uses subroutines to organize its code and to help format its output in neat columns.