Procedures, functions and structured programming
| English | Chinese | Pinyin |
|---|---|---|
| subroutines | 子程序 | zi chéng xù |
| function | 函数 | hán shù |
| procedure | 过程 | guò chéng |
| structured programming | 结构化编程 | jié gòu huà biān chéng |
| decomposition | 分解 | fēn jiě |
| parameters | 参数 | cān shù |
| arguments | 实参 | shí cān |
| signature | 签名 | qiān míng |
| pass by value | 传值 | chuán zhí |
| pass by reference | 传引用 | chuán yǐn yòng |
| global variable | 全局变量 | quán jú biàn liàng |
| local variable | 局部变量 | jú bù biàn liàng |
| scope | 作用域 | zuò yòng yù |
A tape of routines anyone could borrow
- By 1951 the EDSAC team in Cambridge kept a library of subroutines on punched paper tape: square roots, printing, logarithms. Any program could read one in and call it.
- The hard part was getting back. David Wheeler's trick, the "Wheeler jump", stored the return address so a routine could return to wherever it had been called from.
- Every function call you write today does the same thing, and every language library descends from that tape.
- This lesson is procedures and functions: how to define them, how to pass values in and out, and how to write one the way Paper 2 marks it.
Procedures and functions
- Structured programming 结构化编程 builds a program from small named subroutines 子程序, each with one job.
- A procedure 过程 is a named block that does an action and returns nothing:
PROCEDURE Greet(Name : STRING) … ENDPROCEDURE, run withCALL Greet("Ada"). - A function 函数 returns a value that becomes part of an expression:
FUNCTION Square(X : INTEGER) RETURNS INTEGER … RETURN X * X … ENDFUNCTION, used asResult ← Square(5) + 1.

A procedure does something; a function hands back a value
The call stack: push on call, pop on return
Calling a subroutine pushes a new frame on top; returning pops it and hands a value back to the caller. The call that is running is always the frame on top.
The key difference between a procedure and a function is that a function:
A function returns a value (used in an expression); a procedure performs an action and returns nothing.
A function Square(x) returns x * x. What does the call Square(5) return?
5 × 5 = 25 — the value the function hands back to its caller (the frame popped off the call stack).
Where each is appropriate
- A procedure where the same group of steps is needed at several points: validate an input, print a menu, swap two values. The steps are written once and called by name.
- A function where a single value must be calculated and then used in an expression: a total, a
TRUE/FALSEresult, the larger of two numbers. The return value replaces the call. - Use a subroutine when logic appears in more than one place, when a block has a clear named purpose, when the program is complex enough to need decomposition 分解, or when you want to test one piece on its own.
A good reason to write a subroutine is that:
Subroutines remove duplication, give a named purpose, and can be tested in isolation.
Parameters, arguments and the interface
- Parameters 参数 are the variables a subroutine declares to receive values; the values the caller supplies are the arguments 实参.
- The header is the first line:
PROCEDURE Name(Param : TYPE)orFUNCTION Name(Param : TYPE) RETURNS TYPE. The interface, or signature 签名, is the name, the parameters in order with their types, and the return type: everything a caller must know. - The return value is what a function passes back with
RETURN.
Match each term to what it means.
Function vs procedure = returns a value or not; by value vs by reference = copy or original.
Worked example: describe each term in a header
FUNCTION Pass2(Count : INTEGER) RETURNS BOOLEAN.FUNCTION: a subroutine that returns a value.Pass2: the identifier used to call it.Count: the parameter, the identifier that receives the argument passed in.INTEGER: the data type of that parameter.RETURNS BOOLEAN: the data type of the value the function returns. Five parts, one mark each.
In FUNCTION Pass2(Count : INTEGER) RETURNS BOOLEAN, the identifier Count is the ____.
The parameter receives the argument the caller passes in and is used inside the function like a local variable.
Pass by value and pass by reference
- Pass by value 传值: the routine receives a copy, so changes inside it do not reach the caller. Use it for inputs the routine only reads.
- Pass by reference 传引用: the routine receives a reference to the caller's own variable, so changes do reach the caller. Use it when the routine must update the argument, as in
Swap. - Cambridge writes the mode in the header,
BYVALorBYREF, before each parameter. If neither is written,BYVALis assumed.

A copy, or a link to the caller's variable
Worked example: what is output?
PROCEDURE Adjust(BYREF X : INTEGER, BYVAL Y : INTEGER)
X <- X + Y
Y <- Y * 2
ENDPROCEDURE
A <- 5
B <- 3
CALL Adjust(A, B)
OUTPUT A, B
Xis a reference toA, soAbecomes 8.Yis a copy ofB, so doublingYleavesBat 3.- The output is
8, 3. Had the header saidBYVAL X,Awould still be 5.
In the worked example, what is the value of A after CALL Adjust(A, B)?
X is passed BYREF, so X ← X + Y adds 3 to the caller's A: 5 + 3 = 8. B stays 3 because Y was a copy.
Local and global variables
- A local variable 局部变量 is declared inside a subroutine and exists only while it runs; a global variable 全局变量 is declared outside and is visible everywhere. The region where a name is visible is its scope 作用域.
- Locals are preferred: the same identifier can be reused elsewhere without a clash, the value cannot be changed accidentally by other parts of the program, the memory is released on return, and the subroutine is self-contained.
- A local is created new on every call, so it cannot carry a value between calls. A routine that builds up a string over repeated calls needs that string to be global, or passed
BYREF.

A global is visible everywhere; a local lives only inside its own subroutine
A local variable exists only inside the subroutine where it is declared, while a global variable is visible everywhere in the program.
Keeping variables local limits their scope, avoids name clashes, and makes a subroutine testable on its own — globals are best avoided.
Which are benefits of using local variables? Select all that apply.
A local is created fresh on every call, so it cannot keep a value between calls. That is the one job a global, or a BYREF parameter, does instead.
Turning a procedure into a function
- Change
PROCEDUREtoFUNCTIONand addRETURNS <type>to the header. - Replace the
OUTPUT, or theBYREFparameter that carried the result out, with aRETURNstatement. - Change every call so the returned value is used:
Result ← Unpack(Text)instead ofCALL Unpack(Text, Result).
To convert a procedure into a function you change the header to FUNCTION with RETURNS, replace the OUTPUT with RETURN, and change the calls to use the returned value.
Three changes, three marks: the header, the RETURN, and the calls.
Worked example: writing a module for Paper 2
- A global array
Score : ARRAY[1:50] OF INTEGERholds test scores. Write a functionCountAbove(Limit : INTEGER)that returns how many scores are greater thanLimit.
FUNCTION CountAbove(BYVAL Limit : INTEGER) RETURNS INTEGER
DECLARE Index, Count : INTEGER
Count <- 0
FOR Index <- 1 TO 50
IF Score[Index] > Limit THEN
Count <- Count + 1
ENDIF
NEXT Index
RETURN Count
ENDFUNCTION
- The scheme awards a mark per feature: the header with parameter and return type, the local declarations, the counter initialised before the loop, the loop over every element, the condition with the right comparison, the update inside it, the constructs closed, and one
RETURNafter the loop. - An unfinished module still scores for every correct part, so write all of them.

Each part of a module answer carries its own mark
Put the parts of a Paper 2 module answer in the order they are written.
Header, declare, loop, condition, update, return. Each part is a mark, even if another part is wrong.
Marks that slip away
- A routine that must change the caller's variable needs
BYREFin its header; without itBYVALis assumed and the change is lost. - A function has one
RETURN, after the loop, andENDFUNCTION. ARETURNinside the loop ends it on the first element. DECLAREevery local, and initialise a counter or total to 0 before the loop.- "Efficient pseudocode" means moving work that does not change out of the loop, stopping a search at the first match, and not repeating a call whose result could be stored.
To make a loop more efficient, a value that does not change with the loop counter should be:
Hoisting a loop invariant out avoids recomputing the same value on every iteration.
You've got it
- a procedure does an action and is
CALLed; a function returns a value used in an expression - the header names the routine, its parameters with types and the return type; arguments are the values passed in
- BYVAL passes a copy (the default); BYREF lets the routine change the caller's variable
- prefer local variables; a local is new on every call, a global keeps its value
- a Paper 2 module: header, declarations, initialisation, loop, condition, update, closed constructs, one
RETURN