Concepts / Formal and Actual Parameters

Formal and Actual Parameters

Formal parameters are the variables declared in a subroutine's parameter list, and actual parameters are the values or expressions supplied in the call statement.

  • Programming

Predicting Where Parameter Values Come From

Subroutines are reusable blocks of code that perform a task, and they often need outside information to do their work. Parameters are the mechanism that carries that information in. Using a subroutine that already exists usually feels natural: you write the call, supply some values, and get a result back. The difficulty appears when you have to write the subroutine yourself, because then you must decide what the parameter variables are supposed to hold and when they receive their values.

What do you think happens?

A subroutine's parameter list declares three names, and another part of the program calls it with three expressions. Where do the three parameter variables get their values, and at which point in time?

  • The subroutine's first lines assign them fixed values

  • The subroutine asks the user to type them in when it starts

  • The caller's actual values are assigned to them before the subroutine body runs

Reveal answer
Answer:

The caller's actual values are assigned to them before the subroutine body runs.

The computer assigns actual parameter values to formal parameters before it executes the statements inside the subroutine, so the body never needs to set or request them. Keep this prediction in mind, because the rest of the article shows why it is correct and why the other two options reflect a fundamental misunderstanding.

Formal Parameters Versus Actual Parameters

The two terms are easy to mix up because they appear side by side in the same line of code. A useful way to keep them apart is to ask where each one is written. A formal parameter is a variable declared in a function definition, and it is the name the subroutine uses internally. An actual parameter is the value or expression supplied where the subroutine is used, and it is the value the caller provides.

Definition

Formal parameters are the variables declared in a subroutine's parameter list. Actual parameters are the values or expressions supplied in the call statement. A formal parameter is written in the definition; an actual parameter is written at the place where the subroutine is used.

Function definitionCall statementDeclared names andtypesValues or expressionsUsed inside the bodyEvaluated then passeddeclaresreferred to by namesupplieshanded over
Where does each kind of parameter live in the code: the declaration in the function header versus the values written in the call statement?

The formal parameter header only announces that a named slot exists and what kind of data it accepts. The header contains no values. Filling those slots is the job of the call. Keeping this split in mind prevents most of the confusion that follows.

Reading the doTask Call Piece by Piece

The source uses one call as its running example. Read it first, before worrying about vocabulary. A good first habit is to form a prediction about what each piece of the call does, then name the pieces.

java
Notes on the code
  • 17 is a plain value, a literal integer
  • Math.sqrt(z+1) is an expression whose result is a single number
  • z >= 10 is a comparison that produces a true or false result
Worked example

Identifying each actual parameter

List the three actual parameters in the call doTask(17, Math.sqrt(z+1), z >= 10), giving each one's position and what kind of thing it is.

  1. 1
    Locate the parentheses

    The actual parameters sit inside the parentheses of the call, separated by commas.

  2. 2
    Position 1

    The first actual parameter is 17. It is a plain value, so nothing needs to be computed before it is passed.

  3. 3
    Position 2

    The second actual parameter is Math.sqrt(z+1). It is an expression, so its result is what gets passed, not the text of the expression.

  4. 4
    Position 3

    The third actual parameter is z >= 10. It is a comparison, so the value passed is either true or false.

  5. 5
    Keep the order

    The subroutine receives these three values in the order they appear in the call. Changing the order changes which value lands in which formal parameter.

Result

Three actual parameters: a plain value 17 in position 1, an expression Math.sqrt(z+1) in position 2, and a comparison z >= 10 in position 3.

The definition of doTask is not part of the source pack, so its formal parameter names are not given here. What you can rely on is their role: each formal parameter is a placeholder inside the definition that stands for a value supplied later by whoever calls the subroutine. If you need to name them in your own code, you write a header in the definition, as the next illustration shows.

java
Notes on the code
  • This header is a generated illustration, not the course's doTask definition
  • a, b, and c are formal parameters: declared here, with no values
  • The header states only the name and type of each slot

Matching Values to Slots by Position

Matching between actual and formal parameters follows position. The first actual parameter feeds the first formal parameter, the second feeds the second, and so on. The name of the caller's value plays no part in the matching. Only the order matters. The diagram below traces the doTask call into the three formal slots.

17plain valueformal parameter 1Math.sqrt(z+1)expression resultformal parameter 2z >= 10true or falseformal parameter 3position 1position 2position 3
When doTask(17, Math.sqrt(z+1), z >= 10) is called, which actual value lands in which formal parameter slot, and what happens if the positions are swapped?

Notice what the figure does not show. Nothing flows from the subroutine back to the call, and nothing asks for input. The values start in the call statement and end up in the formal parameters. If you swapped the first two actual parameters in the call, the value of Math.sqrt(z+1) would land in the first formal slot and the value 17 would land in the second, which is a different meaning for the same subroutine.

The Order of Events During a Call

Executing the call statement has essentially the same effect as a block of statements that does its work in a fixed order. First, memory locations are allocated for the formal parameters. Then the first actual value is assigned to the first formal parameter. The square root expression is computed and its result assigned to the second formal parameter. The comparison is evaluated and its true or false result assigned to the third. Only after that does the task itself run. The sequence diagram lays out this progression.

Call statementdoTask body1. evaluate 17 and pass it2. evaluate Math.sqrt(z+1) and pass the result3. evaluate z >= 10 and pass true or false4. formal parameters now hold the values5. body runs using those parameters
What happens first, second, and third when the function is called: are the formal parameters assigned before or after the body executes, and where does each value come from?
Code walkthrough
void doTask(int a, double b, boolean c) {
    // formal parameters a, b, c already hold the caller's values here
    System.out.println(a + " " + b + " " + c);
}
  1. 1
    The header declares a, b, and c. It contains no values.
  2. 2
    By the time the first line of the body runs, the caller's values are already in a, b, and c.
  3. 3
    The body therefore reads the parameters directly and never assigns to them or asks for input.
  • Illustrative generated body, not the course's doTask definition

The source is careful about the status of this block-of-statements picture. It is a model of what happens, not a complete description of the machinery. Writing the call as a list of declarations and assignments gives the same overall effect as the one-line call, but the two are not identical in every respect. Use the model to reason about order and meaning, not to predict low-level details.

Mistakes Beginners Make With Parameters

  • Common mistake

    Assigning values to the formal parameters at the top of the body

    What it looks like
    void doTask(int a, double b, boolean c) { a = 17; b = Math.sqrt(z+1); ... }
    Why it fails

    The caller has already supplied the values before the body runs. Overwriting them at the top discards the actual parameters and treats the header as empty slots waiting to be filled.

    Do this instead

    Leave the parameters alone at the top of the body and use them by name, since their values were assigned at call time.

  • Common mistake

    Making the subroutine ask the user for the parameter values

    Why it fails

    This assumes the subroutine must prepare its own inputs. Under the correct model the caller supplies them through the call statement, so the body never needs to request them.

    Do this instead

    Pass the information in through the call's actual parameters, and let the body only use the formal parameters.

  • Common mistake

    Believing the call's positions do not matter because the names look right

    What it looks like

    Swapping the first two actual parameters of doTask(17, Math.sqrt(z+1), z >= 10)

    Why it fails

    Matching follows position, not the look of the expression. The value 17 would land in the wrong formal slot.

    Do this instead

    Check each actual parameter against the position of its matching formal parameter in the definition.

  • Common mistake

    Confusing the formal parameter, which is written in the definition, with the actual parameter, which is written at the call site

Tracing an Unexpected Result Back to a Parameter

When a result is not what you expected, the useful question is where along the chain from call to subroutine the value stopped matching your prediction. Start at the call, not inside the subroutine. Write down the value each actual parameter should have, based on your reading of the call, and compare that with what you expected. If the call's items match your expectations, the divergence lies in what the subroutine does with the values it received. If they do not match, the divergence lies in the call itself.

Call statementPosition 1 valueSubroutine resultPosition 2 valuePosition 3 valuecompare to expectationcompare to expectationcompare to expectationif all match, check bodyif all match, check bodyif all match, check body
If the function returns a wrong result, how do I trace each actual value from the call statement into its matching formal parameter to find which one is in the wrong position?
MEDIUM

A colleague writes the call doTask(z >= 10, 17, Math.sqrt(z+1)) and gets a wrong result. Without looking inside doTask, identify which actual parameter lands in which formal position, and state which position now holds a value of a different kind than the one the original call intended.

Hints
  • Number the actual parameters from left to right, starting at position 1.
  • Compare each position's value kind with the original call, where position 1 was a plain value and position 3 was a comparison.
  • The subroutine receives the values in the order they appear in the call.

Key Takeaways

  • Formal parameters are the variables declared in a subroutine's parameter list or function definition, and actual parameters are the values or expressions supplied in the call statement.
  • The computer assigns actual parameter values to formal parameters before the subroutine body runs, so the body never needs to set or request them.
  • Matching between actual and formal parameters follows position, and expressions in the call are evaluated before their results are assigned.
  • In doTask(17, Math.sqrt(z+1), z >= 10), the three actual parameters are a plain value, an expression, and a comparison, each supplied in a fixed position.
  • When a result is unexpected, check each actual parameter in its position in the call before looking inside the subroutine.