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

Free forever · no card needed

Start free
Intermediate

Subroutines and Recursion

4.1.2 Programming concepts: subroutines, parameters, local/global variables, stack frames, recursion

Aligned to the AQA 7517 specification

Level
Intermediate
Reading time
6 min
Published
13 June 2026
Updated
1 July 2026
On this page
  1. 1.Subroutines: Procedures and Functions
  2. 2.Parameters: Formal and Actual
  3. 3.Variable Scope: Local vs Global
  4. 4.Stack Frames and the Call Stack
  5. 5.Recursion
  6. 6.Worked Example: Fibonacci
  7. 7.Recursion vs Iteration
  8. 8.Common Exam Mistakes

Key takeaways

  • A subroutine is a named reusable block of code; a procedure returns no value while a function always executes a RETURN statement and returns one.
  • Formal parameters are the names in the definition; actual parameters are the values passed at the call. Pass by value copies the value, while pass by reference passes the address so changes affect the original.
  • Local variables exist only while their subroutine runs and cannot be accessed outside it; global variables are declared outside all subroutines and are accessible anywhere.
  • Each subroutine call creates a stack frame on the call stack holding the return address, local variables and parameter values; the frame is popped when the call returns.
  • Every recursive subroutine needs a base case that returns without recursing and a recursive case that calls itself on a smaller input; without a base case the call stack overflows.

Subroutines: Procedures and Functions

A subroutine is a named, reusable block of code that performs a specific task. Subroutines reduce duplication and make programs easier to read, test, and maintain.

Two types:

TypeReturns a value?AQA keyword
ProcedureNoPROCEDURE
FunctionYesFUNCTION / RETURN
PROCEDURE greet(name)
    OUTPUT "Hello, " + name
ENDPROCEDURE

FUNCTION square(n)
    RETURN n * n
ENDFUNCTION

// Calling them:
greet("Alice")          // OUTPUT: Hello, Alice
result ← square(5)     // result = 25

A function must always execute a RETURN statement before it ends. A procedure produces effects (output, modifying data) but returns nothing.

Parameters: Formal and Actual

Formal parameters are the names listed in the subroutine definition. Actual parameters (arguments) are the values passed when the subroutine is called.

FUNCTION add(a, b)          // a and b are formal parameters
    RETURN a + b
ENDFUNCTION

result ← add(10, 20)        // 10 and 20 are actual parameters

Pass by value — a copy of the value is passed; changing the parameter inside the subroutine does not affect the original variable.

Pass by reference — the address of the variable is passed; changes inside the subroutine do modify the original.

// Pass by value (default in AQA pseudocode)
PROCEDURE doubleVal(x)
    x ← x * 2    // Only changes local copy
ENDPROCEDURE

// Pass by reference
PROCEDURE doubleRef(BYREF x)
    x ← x * 2    // Changes the original variable
ENDPROCEDURE

Variable Scope: Local vs Global

Local variables are declared inside a subroutine. They exist only while that subroutine is executing and cannot be accessed from outside it.

Global variables are declared outside all subroutines. They are accessible from anywhere in the program.

globalCount ← 0         // Global variable

PROCEDURE increment()
    localTemp ← 1       // Local variable — only exists here
    globalCount ← globalCount + localTemp
ENDPROCEDURE

increment()
OUTPUT globalCount      // 1
OUTPUT localTemp        // ERROR — localTemp is out of scope

Minimise global variables. They create hidden dependencies between subroutines, making programs harder to debug and test. Prefer passing values as parameters.

Stack Frames and the Call Stack

When a subroutine is called, the processor creates a stack frame on the call stack. The stack frame stores:

  • The return address (where execution resumes after the call)
  • The local variables declared inside the subroutine
  • The parameter values passed to the subroutine

The call chain main() → factorial(3) → factorial(2) → factorial(1) builds up these stack frames (top of stack = most recent call):

As each call returns, its frame is popped off the stack. Deep recursion can exhaust stack space, causing a stack overflow.

Worth saving these ideas?

Turn what you've read into instant revision cards. Free to get started.

Make flashcards

Recursion

A recursive subroutine calls itself. Every recursive definition has two components:

  1. Base case — a condition under which the subroutine returns without calling itself
  2. Recursive case — the subroutine calls itself with a simpler (smaller) input

Without a base case, recursion never terminates and the call stack overflows.

Worked example — factorial:

FUNCTION factorial(n)
    IF n = 0 THEN
        RETURN 1                    // Base case
    ELSE
        RETURN n * factorial(n - 1) // Recursive case
    ENDIF
ENDFUNCTION

Trace for factorial(4):

factorial(4)
= 4 * factorial(3)
= 4 * (3 * factorial(2))
= 4 * (3 * (2 * factorial(1)))
= 4 * (3 * (2 * (1 * factorial(0))))
= 4 * (3 * (2 * (1 * 1)))
= 4 * (3 * (2 * 1))
= 4 * (3 * 2)
= 4 * 6
= 24

Worked Example: Fibonacci

The Fibonacci sequence: 1, 1, 2, 3, 5, 8, 13, …

FUNCTION fib(n)
    IF n <= 1 THEN
        RETURN n                        // Base cases: fib(0)=0, fib(1)=1
    ELSE
        RETURN fib(n - 1) + fib(n - 2) // Recursive case
    ENDIF
ENDFUNCTION

Trace for fib(4):

fib(4) = fib(3) + fib(2)
       = (fib(2) + fib(1)) + (fib(1) + fib(0))
       = ((fib(1) + fib(0)) + 1) + (1 + 0)
       = ((1 + 0) + 1) + 1
       = 3

Note that fib(2) is computed twice in this trace — a key inefficiency of naïve recursion. This is the motivation for dynamic programming (extra context — not required by AQA 7517).

Recursion vs Iteration

AspectRecursionIteration
Code styleOften more concise for naturally recursive problemsExplicit loop; more lines for recursive problems
Memory useEach call adds a stack frame; risk of stack overflowUses a fixed amount of memory
PerformanceFunction call overhead; recomputation of sub-problemsGenerally faster; no call overhead
Best forTree/graph traversal, divide-and-conquer, parsingSimple counting, list processing

Common Exam Mistakes

1. Missing the base case

Without a base case the subroutine calls itself indefinitely, causing a stack overflow. Always identify the base case before writing the recursive case.

2. Confusing pass by value and pass by reference

Pass by value: changes to the parameter inside the subroutine do not affect the calling code's variable. Pass by reference: they do. State which mechanism you are using when writing pseudocode answers.

3. Assuming local variables persist between calls

Each call creates a new stack frame with fresh local variables. A local variable set in one call is gone after that call returns.

4. Off-by-one errors in base cases

factorial(0) = 1 (not factorial(1) = 1). Using 1 as the base case causes factorial(0) to recurse into factorial(-1) and beyond.

Key terms

Subroutine
A named, reusable block of code that performs a specific task, reducing duplication and making programs easier to read, test and maintain.
Procedure
A subroutine that performs effects such as output or modifying data but returns no value, defined with the AQA keyword PROCEDURE.
Function
A subroutine that returns a value and must always execute a RETURN statement before it ends.
Formal parameter
A name listed in the subroutine definition that receives an argument when the subroutine is called.
Actual parameter
An argument: the value passed to a subroutine when it is called.
Pass by value
A parameter-passing mechanism where a copy of the value is passed, so changes inside the subroutine do not affect the original variable.
Pass by reference
A parameter-passing mechanism where the variable's address is passed, so changes inside the subroutine modify the original variable.
Local variable
A variable declared inside a subroutine that exists only while that subroutine runs and cannot be accessed from outside it.
Global variable
A variable declared outside all subroutines that is accessible from anywhere in the program.
Stack frame
A record created on the call stack for each subroutine call, storing the return address, local variables and parameter values.
Call stack
The stack of frames built up by active subroutine calls; a frame is popped when its call returns, and deep recursion can exhaust it.
Base case
The condition in a recursive subroutine under which it returns without calling itself, allowing the recursion to terminate.

Frequently asked questions

A function returns a value and must always execute a RETURN statement before it ends, using the AQA keywords FUNCTION / RETURN. A procedure (keyword PROCEDURE) produces effects such as output or modifying data but returns nothing.

With pass by value a copy of the value is passed, so changing the parameter inside the subroutine does not affect the original variable. With pass by reference the variable's address is passed, so changes inside the subroutine do modify the original.

The base case is a condition under which the subroutine returns without calling itself, which is what makes the recursion terminate. Without it the subroutine calls itself indefinitely, building stack frames until the call stack overflows.

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

Programming Fundamentals

Next

Object-Oriented Programming

Related lessons

7 min

9 min

Lesson

Stacks and Queues

A-Level Computer Science · AQA 7517

2 months ago

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

Start revising free

Free to start. No card needed.