Concepts / Control Statements and Subroutines

Control Statements and Subroutines

Control statements control the flow of a program's execution, which is the order in which its statements are carried out.

  • Programming

Why Programs Need Control Flow

A program is more than a list of instructions that the computer reads from top to bottom. Real programs need to decide what work to do, repeat some work, and skip other work depending on the situation. The tools that make these decisions are called control statements. Their job is to control the flow of a program's execution, meaning the order in which its statements are carried out.

The course material introduces control statements through Interest3.java from Section 3.1, which is the first example in the material that uses control statements. Before you meet the individual control statements, it helps to picture what execution looks like both with and without control. Once you can do that, the specific statements become much easier to read.

A useful picture is a single pointer that moves through the program. The pointer lands on a statement, that statement is carried out, and then the pointer moves on. Keep this pointer in mind through the rest of the article, because every control statement is simply something that can change where the pointer goes next.

Sequential Flow as the Default

When no control statement changes it, execution moves from each statement to the next one in sequence. The pointer goes to the first statement, carries it out, then moves to the statement right after it, and so on until the statements run out. This is the simplest case, and the rest of the topic is about how control statements alter that path.

java
Output
7
Notes on the code
  • The first statement runs first and stores 4 in a
  • The second statement runs next and stores 7 in b
  • The third statement runs last and prints 7

Tracing a Program One Step at a Time

To understand control flow in any program, trace its execution step by step and record the state of the variables after each step. Tracing means you act as the computer: you move the pointer, carry out one statement, write down what changed, and then decide where the pointer goes next. This habit is the main technique for reading programs with control flow, and it works the same way for every program.

java
Notes on the code
  • n is assigned 7 first
  • The if tests n % 2 == 0, which checks whether n is even
  • The else block holds the statement that runs when the test is false
  • The last statement always runs after the if-else is finished

What do you think happens?

What does the program print, and in what order?

Reveal answer
Answer:

It prints odd and then done. The even line is never carried out.

The test n % 2 == 0 is false because 7 % 2 is 1. Execution therefore takes the else path and prints odd. The statement that prints done is not part of the if-else, so it runs afterward.

int n = 7n holds 7n % 2 == 07 % 2 is 1, so falseprint oddoutput: oddprint doneoutput: donenextfalsenext
At each step of the program, which statement runs next, and how do the values change?

Read the state diagram from top to bottom. The value 7 is stored first. The condition is tested with the current value, and because 7 % 2 is 1, the condition is false. The pointer then takes the false path to the statement that prints odd. The statement that prints even is never reached for this value, even though it appears in the source code. If you change the value of n, the path changes while the code itself stays the same.

What a Control Statement Changes

Definition

A control statement determines which statements run next, so the same code can take different paths depending on values at run time.

An ordinary statement, such as an assignment or a print, does its work and then lets the pointer move to the next statement in the sequence. A control statement does its work too, but it also decides where the pointer goes next. The sequence is the default, and a control statement is the thing that can override it.

FeatureOrdinary statementControl statement
What it doesCarries out its own workDecides which statements run next
Where the pointer goes nextThe next statement in sequenceA path chosen by the statement, based on values at run time
Effect on the same codeAlways runs when reachedThe same code can take different paths on different runs

Ordinary and control statements differ in what they do to the order of execution.

Choosing Between Two Branches

A common pattern is a decision with two branches. The program evaluates a condition, and the result of that condition decides which branch runs. To trace a decision, evaluate its condition with the current values, and then follow only the matching branch. After the branch finishes, the two paths rejoin and the pointer continues with the statement after the decision.

n = 7n % 2 == 0false for 7print evenskippedprint donepaths rejoinprint oddrunstruefalse
When the condition is tested, which statements run, which are skipped, and where do the paths rejoin?

The figure shows the two possible paths. For the value 7, the condition is false, so the false edge is taken and print odd runs. The print even statement is skipped. The two paths rejoin at print done, which runs for every value of n. Changing n to 8 would send the pointer down the true edge instead, and the same code would print even.

Subroutines and Reuse

Definition

A subroutine is a block of code written once and called from several places, often with different input values.

A subroutine lets a program reuse a block of code instead of writing it again at each place it is needed. When a subroutine is called, execution moves into its block. When the subroutine finishes, execution returns to the caller and continues from where the call was made. The same block can be called many times, and each call can pass in a different input value.

java
Output
6
20
Notes on the code
  • twice is defined once as a block of code
  • main calls twice with 3, and the result 6 is stored in a
  • main then calls twice with 10, reusing the same block
  • The body of twice does not change between the two calls

Following a Call and Return

When main reaches the call twice(3), execution moves into the twice block with x set to 3. When twice finishes with its return statement, execution goes back to the caller and continues in main. The diagram shows the state at the moment twice is running for the first call. The block that is active is shown at the top, and the caller that is waiting to continue is shown below it.

mainwaiting for twicetwicex = 3, runningcall twice(3)
When main calls twice, where does execution jump to, and where does it resume after twice finishes?
  1. 1
    main reaches the call twice(3) and execution moves into the twice block with x set to 3
  2. 2
    twice runs its return statement and produces 6, so the block finishes
  3. 3
    Execution returns to main, which continues with the statement after the call and stores 6
  4. 4
    main reaches the call twice(10), which starts a new activation of the same block with x set to 10
  5. 5
    twice produces 20, the block finishes, and execution returns to main to continue

After twice returns 6, that block is finished and only main remains. The next call, twice(10), starts a new run of the same block with x set to 10. The code of twice did not change between the two calls. Only the value passed in was different.

Mistakes Learners Make with Control Flow

  • Common mistake

    Assuming every statement in the source code runs

    What it looks like

    Reading the odd or even program and expecting both print statements to run for n = 7

    Why it fails

    A decision sends execution down only one branch for the current values, so the other branch is skipped

    Do this instead

    Evaluate the condition with the current values and follow only the matching branch

  • Common mistake

    Tracing a program without recording the variable values

    What it looks like

    Stepping through the program in your head but forgetting that n holds 7 after the first line

    Why it fails

    A condition depends on values at run time, so you cannot decide the path without knowing the state

    Do this instead

    Write down the state of the variables after each step, as the hand trace does

  • Common mistake

    Thinking a subroutine runs only once because it is written once

    What it looks like

    Believing that twice has only one result because its definition appears once in the file

    Why it fails

    A subroutine is written once but can be called from several places, each with its own input

    Do this instead

    Follow each call separately, noting the input value and the result returned

  • Common mistake

    Forgetting where execution resumes after a call

    What it looks like

    Assuming the program jumps to the statement after the subroutine definition when twice finishes

    Why it fails

    Execution returns to the caller, and continues from the point where the call was made

    Do this instead

    After the subroutine finishes, return to the statement in the caller that made the call

Practice Tracing Flow

EASY

Trace the odd or even program with n set to 8 instead of 7. Write down the value of n, the result of the test, the branch taken, and the output after each step. Then say which line is skipped and whether the final line still runs.

Hints
  • Compute 8 % 2 before deciding which branch the condition selects
  • The branch that prints even is taken when the condition is true
  • The line that prints done is after the if-else, so it runs for every value of n
MEDIUM

Using the twice subroutine from this article, write out the order of execution for a program that calls twice(4) and then twice(7). For each call, state the value of x, the value returned, and the statement in main where execution resumes.

Hints
  • Each call starts a new run of the same block with a new value of x
  • The block finishes at its return statement, and execution goes back to the caller

Key Takeaways

  • A control statement controls the flow of a program's execution, which is the order in which its statements are carried out, and decides which statements run next
  • With no control statement changing it, execution moves from each statement to the next one in sequence
  • To trace a program, follow the flow one step at a time, record the variable values after each step, and at a decision follow only the branch the current values select
  • A subroutine is a block of code written once and called from several places, often with different inputs; execution moves into it on a call and returns to the caller when it finishes
  • Interest3.java from Section 3.1 is the first example in the material that uses control statements, and ThreeN2.java is cited as an example that uses subroutines