Functions and Procedures

8 min✏️ Quiz at the end

The Copy-Paste Trap

Your program greets players: three lines to print a border, a welcome, and the date. Players are greeted in five different places, so you paste the three lines five times. Then the design changes… and you must find and fix all five copies. Miss one and you have a bug — the sneaky kind, where the program mostly works.

Every programmer falls into this trap exactly once. The way out is the most powerful idea in programming: name a block of instructions, and reuse it by name.

Functions: Instructions with a Name

A function (also called a procedure or subroutine) is a named block of code. Define it once; call it by name wherever needed. In pseudocode:

FUNCTION greet(name)
    OUTPUT "*******************"
    OUTPUT "Welcome, ", name, "!"
    OUTPUT "*******************"
ENDFUNCTION

greet("Aisha")
greet("Ben")

Two greetings, one definition. When a call happens, execution jumps into the function, runs its lines, and returns to where it left off. The design change now touches one place, and all calls everywhere are instantly updated.

Parameters: The Function's Inputs

Notice name in brackets. That is a parameter — a value the caller passes in, so one function serves many situations. greet("Aisha") and greet("Ben") run identical instructions on different data. Inside the function, name behaves like a local variable holding whatever was passed.

Functions can take several parameters: drawRectangle(width, height, colour). Parameters are what turn a function from a recording into a machine — same mechanism, any input.

Return Values: The Function's Output

Some functions compute an answer and hand it back — a return value:

FUNCTION square(n)
    RETURN n * n
ENDFUNCTION

area ← square(5)        ← area is now 25

The call square(5) becomes its result, so it can sit anywhere a value can: in an assignment, inside a condition — even inside another call: square(square(2)) is square(4) is 16.

A function is thus a miniature program with its own inputs and outputs: parameters in, return value out. (The traditional naming: a function returns a value; a procedure just performs actions, like greet. Many modern languages call both "functions" — the idea matters more than the label.)

Building Programs Like LEGO

Functions transform how programs are designed, not just written. Decompose a game into parts, and each part becomes a function:

FUNCTION playGame()
    setupBoard()
    WHILE NOT gameOver()
        takeTurn()
        updateScore()
    ENDWHILE
    showWinner()
ENDFUNCTION

Read that aloud — it is the plan of the game, legible in five lines, because every messy detail lives inside a named function. And each of those functions may call further functions of its own.

This is abstraction made of code: to use gameOver() you only need its name and its promise — you never need to reread its insides. You already trust this daily: whoever wrote your language's print function, you have called it happily without once inspecting it. Functions also make testing tractable: each small piece can be checked alone, then trusted as a building block.

Try It Yourself

In pseudocode, write larger(a, b) that returns the bigger of two numbers. Then — without touching its insides — use it to find the largest of three numbers in one line. (Hint: larger(a, larger(b, c)) — functions feeding functions.) Finally trace it with 4, 9, 2 to confirm.

Worked Example — A Function Calling a Function

Here is a slightly bigger design, showing functions built out of other functions — exactly how real programs grow:

FUNCTION isEven(n)
    RETURN (n MOD 2 = 0)
ENDFUNCTION

FUNCTION countEvens(numbers)
    count ← 0
    FOR EACH n IN numbers
        IF isEven(n) THEN
            count ← count + 1
        ENDIF
    NEXT
    RETURN count
ENDFUNCTION

total ← countEvens([3, 8, 5, 12, 7, 4])
OUTPUT total

Trace it: isEven is called once per item in the list — for 3 (false), 8 (true), 5 (false), 12 (true), 7 (false), 4 (true) — and count climbs to 3 each time a true result comes back. countEvens never needs to know how isEven decides odd from even; it only needs to trust the answer. That trust is exactly the abstraction this lesson keeps returning to: a well-named function with a clear job becomes a building block you can rely on, freeing you to think about the next level of the problem instead of re-deriving every detail each time.

Why Functions Make Testing Easier

One quiet benefit of functions deserves its own spotlight: they make testing dramatically simpler. Without functions, checking whether "even-number counting" works correctly means running the entire program and hoping you notice if that one part is wrong. With isEven and countEvens as separate, named functions, each can be tested in isolation — call isEven(4) directly and confirm it returns true, call isEven(7) and confirm false, entirely separately from the rest of the program. When a bug does appear, functions also narrow the search: if countEvens gives the wrong total, you can test isEven on its own first to rule it in or out, rather than debugging the whole program at once.

Key Words

  • Function / procedure — a named, reusable block of instructions
  • Call — running a function by using its name
  • Parameter — a value passed into a function
  • Return value — the result a function hands back to its caller
  • Reuse — write once, call anywhere; the cure for copy-paste code