Concepts / Writing Functions and Subroutines

Writing Functions and Subroutines

A function is written like a regular subroutine, with the addition that you must specify the value it returns.

  • Programming

Getting Values Back from Calls You Already Make

You have already used functions without writing any yourself. Math.sqrt computes a square root, and TextIO.getInt reads an integer that the user types. In both cases the function gives your program a value, and the program can then store it, print it, or use it in a further calculation.

The natural next question is how to write functions of your own that provide a value in the same way. The answer is the return statement. Once you know its syntax and where it sits inside a function, you can write a function that computes a result and delivers it back to whatever part of the program called it. This article focuses on the syntax first, then on how to read a return statement and predict what it produces.

Anatomy of a Return Statement

A function is written in much the same way as a regular subroutine. Its overall form is the same, with one addition: you must specify the value that the function is to return. The return statement is the place where that value is specified.

Definition

A function is written like a regular subroutine, with the addition that you must specify the value it returns. A return statement has the form return followed by an expression, and that expression supplies the value handed back.

The template has two parts. The keyword return begins the statement. The expression that follows it is the value to be returned. An expression is anything that produces a value, such as a single variable name, a number, or a calculation. The source writes the template with a closing semicolon, and that semicolon is part of the notation as the source presents it. The part of the syntax to learn above all is the keyword followed by an expression.

returnkeyword that begins thestatementtotal times 2expression that isevaluated to give thereturned valuesemicolonclosing punctuation in thesource's notation
What are the component parts of a return statement, and how do they fit together in order?

Read the strip from left to right. The keyword is the anchor of the statement, and the expression is the part that gets evaluated. The expression is what determines the result. If you change the expression from total times 2 to total plus 2, the returned value changes, while the keyword stays exactly the same. So when you read any return statement, the first question to ask is what its expression evaluates to at the moment the function runs.

Evaluating the Return Expression

Before reading on, try to work out what the following function gives back. It takes one number, and its return statement names an expression built from that number. The function is shown as a generated illustration of the pattern the source describes, with an input of 4.

java
Notes on the code
  • The keyword return begins the statement.
  • The expression total * 2 is evaluated using the input total.
  • Only the result of the expression leaves the function.

What do you think happens?

The call is doubleIt(4). What does the program print?

  • 4

  • 8

  • 2

  • 16

Reveal answer
Answer:

8

The return statement hands back the value of its expression, not the input. The expression total * 2 is evaluated with total equal to 4, giving 8, and only that 8 leaves the function. The 4 is the input, which never comes back out by itself.

Output
8
Worked example

Tracing the value from call to printed output

Trace what happens when the main program executes System.out.println(doubleIt(4)).

  1. 1
    Step 1: the call

    The main program calls doubleIt and passes in 4, so the input total starts out as 4.

  2. 2
    Step 2: the expression

    The return statement's expression total * 2 is evaluated with total equal to 4, producing 8.

  3. 3
    Step 3: the hand-back

    Only the value 8 leaves the function. The call is finished once the expression has been handed back.

  4. 4
    Step 4: the place of the call

    The value 8 appears where the call was made, so println prints 8.

Result

The program prints 8, not 4.

This is the central idea of the return statement. The function sends a computed value back to the place where it was called. The return statement is the last thing the function does with its value, so once the expression has been evaluated and handed back, the call is complete.

Subroutines Are Written Once and Called Many Times

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.

Definition

A subroutine is a block of code that can be called multiple times from different parts of a program. It runs when the program reaches a point where it calls it, not merely because it exists in the program.

The important word is called. 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. Writing the instructions in one place means that a change to the job is made once rather than in every place the job is needed.

main programrunning the line with thecalldoubleItrunning its body with totalset to 4main programresumesuses the returned 8 at thecall sitecall with 4return 8
When main calls a subroutine, where does execution go, and where does it come back to after the return?

The diagram shows the path a single call takes. Control leaves the main program at the call, runs the subroutine's body, and returns to the place where the call was made. For a function, the return statement is what determines the value that travels back along that return path.

Tracing Repeated Calls in One Run

Because a subroutine runs only when it is called, the order of the run is set by the main program. Suppose a main program calls the same subroutine at three different points. Each time the main program reaches a call, it pauses its own work, the subroutine runs, and then the main program carries on from the next line after that call.

main programmakes three calls in ordersubroutinesame block of code eachtimecall 1return 1call 2return 2call 3return 3
In what order do the main program and the subroutine take turns running across all of the calls?

Read the diagram from top to bottom. The main program never runs the subroutine on its own; every run of the subroutine begins with a call from the main program and ends with a return to it. The same block of code appears three times in the sequence, but it is written only once in the program.

Function Versus Regular Subroutine

A function and a regular subroutine share the same overall form. What a function adds is the requirement to specify the value it returns. A regular subroutine does not need a value to be handed back in this way, so its written form ends without a return of a computed value.

AspectRegular subroutineFunction
Overall formBlock of code that can be called many timesSame overall form as a regular subroutine
CallingRuns when the program reaches a callRuns when the program reaches a call
Value handed backNo value is specified by a return statementMust specify the value returned, using return followed by an expression
What comes backNot applicable in this comparisonThe result of evaluating the expression, not the input

What stays the same and what a function adds, based on the source's description

Finding the Return Statement Behind a Surprise

When a program prints a number you did not expect, the source recommends a fixed order of checks. Follow the chain in this order: the call, the expression in the return statement, and then the value that appears where the call was made. Checking the return statement and the expression feeding it comes first.

  • Common mistake

    Assuming the function returns its input

    What it looks like

    With doubleIt(4) the programmer expects 4 to come back.

    Why it fails

    The return statement hands back the value of its expression, not the input. The expression is evaluated first, and only its result leaves the function.

    Do this instead

    Evaluate total * 2 with total equal to 4, which gives 8, and expect 8 at the call site.

  • Common mistake

    Looking at the call site first and not the return statement

    What it looks like

    A printed 14 is blamed on println, and the function is never opened.

    Why it fails

    The value printed is whatever the return statement handed back. The call site only shows where that value appears.

    Do this instead

    Open the function, read its return statement, and evaluate the expression before examining anything else.

  • Common mistake

    Changing the keyword instead of the expression

    Why it fails

    The keyword return stays the same in every return statement. The expression is what determines the result.

    Do this instead

    When the result is wrong, change or inspect the expression after return, not the keyword.

Subroutines in ThreeN2.java

The source 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 gives two reasons for the subroutines: code organization and output formatting.

Code organization means that separating the work into named blocks makes the program easier to read and manage. Output formatting means that the program prints its results in neat columns, and the subroutines are part of how that formatting is achieved.

Checking Your Prediction on a Changed Expression

EASY

Keep the same doubleIt function and call, but change its return statement so that the expression is total plus 2 instead of total times 2. Predict what the program now prints for the call doubleIt(4), then check your prediction by evaluating the new expression with total equal to 4.

Hints
  • The keyword return stays the same. Only the expression after it changes.
  • Evaluate the new expression with total equal to 4 before looking at the printed result.
  • Only the value of the expression leaves the function, so ask which number that expression produces.

Key Takeaways

  • A function is written like a regular subroutine, with the addition that you must specify the value it returns through a return statement.
  • A return statement has the form return followed by an expression. The value handed back is the result of evaluating that expression, not the input passed to the function.
  • A subroutine is a block of code that runs whenever a program calls it, so writing it once lets the program reuse it at many points in one run.
  • When a result is unexpected, check the return statement and the expression feeding it first, then the value that appears where the call was made.
  • ThreeN2.java uses subroutines for code organization and for printing its output in neat columns.