Concepts / Subroutines and Modularity

Subroutines and Modularity

A subroutine is a named group of instructions for a specific task.

  • Programming

Writing the Same Job Once

Imagine a program that needs the same job done in three different places. One option is to copy the same lines of code three times. The other option is to write those lines once and let the rest of the program use them whenever they are needed. The second option is the idea behind a subroutine. A subroutine is a block of code that can be called multiple times from different parts of a program.

Before reading on, pause and ask yourself: if a program needs the same calculation or the same printed output in several places, where would you rather keep the instructions for it, in one place or in every place it is needed? The main idea of subroutines is an answer to that question.

What do you think happens?

If a subroutine is written into a program but the program never reaches a point where it is called, does the subroutine run?

  • Yes, it runs as soon as it appears in the file

  • No, it runs only when the program calls it

Reveal answer
Answer:

No, it runs only when the program calls it

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.

Following Calls Through a Run

A subroutine is a named group of instructions for a specific task. Grouping the instructions and giving them a name is what lets the rest of the program refer to the whole group with a single word. The name serves as a compact substitute for the instructions it represents. When the program reaches that name at a point where it calls the subroutine, the instructions stored under the name are carried out.

Because the same block can be called more than once, one piece of code can serve many moments in a single run of the program. The diagram below traces the control flow for a main program that calls the same subroutine three times. Each arrow pointing to the subroutine is a call, and each arrow pointing back is the return. After each return, the main program continues from the point where it left off.

Main programSubroutinecall 1return 1, resume maincall 2return 2, resume maincall 3return 3, resume main
When the main program calls the same subroutine three times, in what order does control jump to the subroutine and return, and where does execution resume each time?

Dividing a Large Program

A large program may need to handle many different tasks. Trying to design all of those tasks as one undivided block makes the program difficult to manage. A subroutine offers a way to separate one task from the rest: its instructions are grouped together, and the group receives a name. This separation is the basis of modularity, the idea that a large program can be divided into manageable units.

Subroutines also change how a programmer approaches a problem. Suppose a program draws a house as one of its tasks. While creating a house-drawing subroutine, attention can stay on drawing the house rather than on every other part of the program. Once that task is organized into a subroutine, the larger design can treat house drawing as an already-solved part of the program. This is what the source means by helping programmers focus on one design problem at a time.

Main programHouse-drawingsubroutineAnother tasksubroutinecallscalls
How are the main program and its subroutines arranged, and which parts of the program does each subroutine own?

Reuse Instead of Copying

Writing a subroutine once lets the program reuse it at many points, so repeated work does not have to be written out again each time it is needed. The following pseudocode is an illustrative example, not source code. It shows the same drawing job written in three places, first by copying the instructions, then by defining one subroutine and calling it.

Notes on the code
  • The copied version repeats three lines three times, so any change must be made in three places.
  • The subroutine version stores the three lines once under the name draw_house.
  • Each call draw_house line runs the stored instructions at that point in the run.
Before

draw roof, draw walls, draw door (copy 1) draw roof, draw walls, draw door (copy 2) draw roof, draw walls, draw door (copy 3)

Three separate copies of the same instructions

After

define subroutine draw_house: draw roof, draw walls, draw door call draw_house call draw_house call draw_house

One stored set of instructions, called three times

Stepping Through Repeated Calls

Worked example

Tracing a Main Program That Calls One Subroutine Three Times

A main program reaches three points where it needs the same job done. The job is stored in one subroutine. Trace what happens at each point.

  1. 1
    First call

    The main program reaches the first call. Control jumps to the subroutine, and its instructions run.

  2. 2
    First return

    When the subroutine finishes, control returns to the main program at the point just after the first call, and the main program continues.

  3. 3
    Second call

    Later in the same run, the main program reaches the second call. Control jumps to the same stored instructions again.

  4. 4
    Second return

    The subroutine finishes and control resumes the main program after the second call.

  5. 5
    Third call and return

    The third call repeats the pattern. The single block of code served three moments in one run.

Result

The subroutine's instructions ran three times, but they were written only once. Each time, execution resumed in the main program right after the call that started it.

EASY

A main program calls a subroutine named print_header at four places. How many times do the instructions inside print_header run during one run of the program, and how many times are those instructions written in the source file?

Hints
  • A subroutine runs each time the program reaches a call to it.
  • Writing a subroutine once means its instructions appear in the file once, no matter how many calls there are.

Subroutines in ThreeN2.java

The source points to ThreeN2.java as a concrete program that uses subroutines. 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 gives two reasons the program 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 subroutines are part of how the results are printed in neat columns.

Common Mistakes With Subroutines

  • Common mistake

    Expecting a subroutine to run just because it is written in the program

    Why it fails

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

    Do this instead

    Check that a call to the subroutine appears at each place where the task is needed.

  • Common mistake

    Copying the same instructions into several places instead of calling one subroutine

    Why it fails

    Copies must all be updated separately whenever the task changes, which makes errors easier to introduce.

    Do this instead

    Write the instructions once under a name and call that name wherever the task is needed.

  • Common mistake

    Treating the subroutine name as a separate job from its instructions

    Why it fails

    The name is a compact substitute for the instructions it represents, not a different task.

Checking Your Understanding

MEDIUM

A program needs the same printed output in five different places. Describe two ways to organize the instructions for that output, and explain which one matches the source's idea of a subroutine and why.

Hints
  • Think about whether the instructions are copied into each place or stored once and called.
  • The source says a subroutine is a block of code that can be called multiple times from different parts of a program.

Key Takeaways

  • A subroutine is a named group of instructions for a specific task, and its name stands in for those instructions.
  • A subroutine runs only when the program calls it, and the same subroutine can be called many times in one run, with execution resuming after each call.
  • Subroutines divide a large program into manageable units and let a programmer focus on one design problem at a time.
  • Writing repeated work once as a subroutine reduces copied instructions, and ThreeN2.java uses subroutines to organize code and format its output.