Track progress, take quizzes and save notes on this lesson.

Free forever · no card needed

Start free
Intermediate

Subroutines: Procedures and Functions

3.2.10 Structured programming and subroutines

Aligned to the AQA 8525 specification

Level
Intermediate
Reading time
9 min
Published
8 June 2026
Updated
1 July 2026
On this page
  1. 1.What Are Subroutines and Why Use Them
  2. 2.Procedures
  3. 3.Functions and Return Values
  4. 4.Parameters and Arguments
  5. 5.Local Variables and Scope
  6. 6.Advantages of Structured Programming
  7. 7.Common Exam Mistakes

Key takeaways

  • A subroutine is a named, self-contained block of code that performs a specific task and can be called from anywhere, after which control returns to the point of the call.
  • A procedure performs an action and returns no value, while a function calculates a result and returns it to the caller using RETURN; every function must have at least one RETURN statement.
  • A parameter is a variable listed in the subroutine's definition; an argument is the actual value supplied when it is called, and arguments are matched to parameters by position.
  • A local variable is declared inside a subroutine and exists only while it executes; a global variable is declared outside all subroutines and accessible anywhere. Locals are preferred as they avoid name conflicts.
  • Structured programming organises a program as a hierarchy of subroutines, making it easier to read, test, maintain and reuse, and allowing parallel development by multiple programmers.

What Are Subroutines and Why Use Them

A subroutine is a named, self-contained block of code that performs a specific task. It can be called from anywhere in a program, executed, and then control returns to the point of the call.

Without subroutines, the same code must be written out in full every time it is needed. With subroutines, it is written once and called by name wherever it is required.

Two types of subroutine:

TypeReturns a value?Typical purpose
ProcedureNoPerforming an action — displaying output, updating data, drawing to screen
FunctionYesCalculating and returning a result for the caller to use

Why subroutines matter:

  • Reuse — write once, call many times; no duplicated code
  • ReadabilitycalculateGrade(score) communicates intent; 20 lines of inline logic does not
  • Maintenance — fixing a bug inside one subroutine fixes it everywhere that subroutine is called
  • Testing — each subroutine can be tested in isolation with known inputs before the full program runs
  • Team development — different programmers can work on different subroutines simultaneously

A well-structured program's main body reads almost like a plan: validateInput(), processData(), displayResults(). The implementation detail of each step is hidden inside its subroutine.

Procedures

A procedure is a subroutine that performs an action and does not return a value to the caller. It is defined once and called by name wherever needed.

SUBROUTINE displayWelcome()
    OUTPUT "Welcome to the quiz!"
    OUTPUT "You have 3 attempts."
ENDSUBROUTINE

displayWelcome()    # call the procedure
def display_welcome():
    print("Welcome to the quiz!")
    print("You have 3 attempts.")

display_welcome()

Worked example — A procedure that draws a horizontal line of a given length. Calling it with different arguments produces different outputs without rewriting the loop:

SUBROUTINE drawLine(length)
    FOR i ← 1 TO length
        OUTPUT "-"
    NEXT i
ENDSUBROUTINE

drawLine(20)    # prints 20 dashes
drawLine(10)    # prints 10 dashes

length is a parameter — a variable defined in the subroutine header that receives the value passed in by the caller. Each call can pass a different value; the subroutine behaves accordingly.

Procedures are the right choice when the task is an action (drawing, saving, logging, displaying) and the caller does not need any value back.

Functions and Return Values

A function is a subroutine that calculates a result and sends it back to the caller using RETURN. The caller can use the returned value directly in an expression, store it in a variable, or pass it to another function.

FUNCTION square(n)
    RETURN n * n
ENDFUNCTION

result ← square(7)
OUTPUT result    # 49
def square(n):
    return n * n

result = square(7)
print(result)    # 49

Every function must have at least one RETURN statement. A function that does not return a value is a procedure, not a function. In AQA pseudocode, forgetting RETURN means the function hands back nothing — the caller receives no value.

Worked example — A function that returns the area of a rectangle:

FUNCTION rectangleArea(width, height)
    RETURN width * height
ENDFUNCTION

lounge ← rectangleArea(5, 4)
kitchen ← rectangleArea(3, 3)
OUTPUT "Total area: " & STR(lounge + kitchen) & " m²"    # Total area: 29 m²

Worked example — A function that checks whether a score earns a grade:

FUNCTION getGrade(score)
    IF score ≥ 70 THEN
        RETURN "Distinction"
    ELSE
        IF score ≥ 40 THEN
            RETURN "Pass"
        ELSE
            RETURN "Fail"
        ENDIF
    ENDIF
ENDFUNCTION

OUTPUT getGrade(82)    # Distinction
OUTPUT getGrade(55)    # Pass

Parameters and Arguments

A parameter is a variable listed in the subroutine's definition. An argument is the actual value supplied when the subroutine is called. Parameters receive their values from arguments at the moment of the call.

SUBROUTINE greet(name, score)        # name and score are parameters
    OUTPUT "Hello " & name & ", your score is " & STR(score)
ENDSUBROUTINE

greet("Alice", 87)                   # "Alice" and 87 are arguments
greet("Bob", 54)

Multiple parameters are matched to arguments by position — the first argument goes to the first parameter, the second to the second, and so on.

ParameterCall 1 argumentCall 2 argument
name"Alice""Bob"
score8754

Worked example — A function with three parameters that checks a value is within bounds:

FUNCTION inRange(value, minVal, maxVal)
    IF value ≥ minVal AND value ≤ maxVal THEN
        RETURN TRUE
    ELSE
        RETURN FALSE
    ENDIF
ENDFUNCTION

OUTPUT inRange(75, 0, 100)    # TRUE
OUTPUT inRange(105, 0, 100)   # FALSE
OUTPUT inRange(-1, 0, 100)    # FALSE

Parameters only exist during the execution of the subroutine. When the subroutine ends, its parameters and local variables are destroyed. The caller cannot access them after the call returns.

How much of this have you taken in?

Quiz yourself on this section, free, no card needed.

Test myself

Local Variables and Scope

Scope defines where in a program a variable can be read or modified.

A local variable is declared inside a subroutine. It exists only while that subroutine is executing and cannot be accessed from outside it.

A global variable is declared outside all subroutines. It can be accessed from anywhere in the program.

totalScore ← 0           # global variable

FUNCTION addBonus(base)
    bonus ← 10           # local variable — only exists inside this function
    RETURN base + bonus
ENDFUNCTION

totalScore ← addBonus(80)    # totalScore is now 90
OUTPUT bonus                 # ERROR — bonus does not exist here

Why local variables are preferred over global variables:

Global variablesLocal variables
Who can modify themAny part of the programOnly the owning subroutine
Debugging difficultyHigh — an error could originate anywhereLow — the subroutine is fully self-contained
ReusabilityCreates hidden dependenciesSubroutine works independently; reuse anywhere
Name conflictsA variable named count in one place conflicts with count elsewhereTwo subroutines can both use count — they are separate local variables

Two different subroutines can use the same identifier (e.g. total, count, i) for their local variables without conflict. They are completely separate locations in memory.

Advantages of Structured Programming

Structured programming organises a program as a hierarchy of subroutines: a top-level main program delegates to mid-level routines, which delegate further to low-level utility functions. Each subroutine has a single, clearly defined responsibility.

Benefits required by the specification:

AdvantageExplanation
Easier to readThe main program reads like a high-level plan; implementation detail is hidden in subroutines
Easier to testEach subroutine can be tested independently with known inputs before the full program is assembled
Easier to maintainA bug fix in one subroutine fixes it everywhere that subroutine is used; changes are localised
ReusabilityA tested, working subroutine can be used in other programs without modification
Parallel developmentMultiple programmers can work on different subroutines simultaneously

Worked example — top-down design for a quiz program:

# Main program — reads like a plan
username ← getUsername()
IF validateLogin(username) THEN
    score ← runQuiz()
    displayResult(score)
    saveResult(username, score)
ENDIF

Each call delegates to a subroutine. A reader understands the program's structure without knowing the implementation of any individual subroutine.

Exam questions about the advantages of subroutines require specific, detailed answers — not just "it makes the code better." Always link the advantage to a concrete consequence: "easier to test because each subroutine can be run independently with known inputs, confirming its output is correct before integrating it into the larger program."

Common Exam Mistakes

1. Confusing procedures and functions

A procedure performs an action and returns nothing. A function calculates and returns a value. If a question asks for a function that returns the larger of two numbers, using OUTPUT instead of RETURN scores zero for that part — the calling code receives no value.

2. Forgetting RETURN in a function

A function without RETURN returns nothing to the caller. Every function must reach a RETURN statement during execution. Check that all branches of an IF...ELSE inside a function contain a RETURN.

3. Accessing a local variable outside its subroutine

Variables declared inside a subroutine do not exist outside it. If a value needs to be available to the calling code, the function must RETURN it, or — less ideally — the subroutine must modify a global variable.

4. Passing arguments in the wrong order

If a subroutine is defined as SUBROUTINE drawRect(width, height), calling drawRect(height, width) silently swaps the values. There is no error message — it just produces the wrong result. Always match argument order to the parameter definition.

5. Writing duplicated code instead of calling a subroutine

If the same block of logic appears in two places in a program, it should be extracted into a subroutine. Duplicated code means two places to fix when a bug is found, two places to update when requirements change, and double the chance of inconsistency.

Key terms

Subroutine
A named, self-contained block of code that performs a specific task and can be called from anywhere in a program.
Procedure
A subroutine that performs an action and does not return a value to the caller.
Function
A subroutine that calculates a result and sends it back to the caller using a RETURN statement.
Parameter
A variable listed in a subroutine's definition that receives a value passed in by the caller.
Argument
The actual value supplied when a subroutine is called, matched to a parameter by position.
Local variable
A variable declared inside a subroutine that exists only while that subroutine is executing and cannot be accessed from outside it.
Global variable
A variable declared outside all subroutines that can be accessed from anywhere in the program.
Scope
The part of a program where a variable can be read or modified.
Structured programming
Organising a program as a hierarchy of subroutines, each with a single, clearly defined responsibility.

Frequently asked questions

A procedure performs an action, such as displaying output, and does not return a value to the caller. A function calculates a result and sends it back to the caller using RETURN, so the caller can use that value in an expression, store it, or pass it on.

A parameter is a variable listed in the subroutine's definition, while an argument is the actual value supplied when the subroutine is called. Parameters receive their values from arguments at the moment of the call, matched by position.

Local variables can only be modified by their owning subroutine, making bugs easier to trace and the subroutine self-contained and reusable. They also avoid name conflicts, since two subroutines can use the same identifier as separate local variables without clashing.

Generate revision on any topic you study

Type any topic you're studying and Aicademy generates a complete lesson, quiz, and flashcard set, personalised to your level.

Lessons on anything

Structured, level-matched lessons on any topic you study

Practice quizzes

Find out what you actually know before the exam does

Flashcard sets

Lock in key concepts with instant revision cards

Ask Aica

Stuck on something? Get a clear explanation, any time

Prev

Arrays and Records

Next

Robust and Secure Programming

Related lessons

8 min

8 min

Lesson

Arrays and Records

GCSE Computer Science · AQA 8525

1 month ago

Top students don’t revise more. They revise what counts.

Start revising free

Free to start. No card needed.