Subroutines and Structured Programming
Procedures and functions, parameters and return values, local and global scope, and why breaking a program into named pieces is the difference between code you can maintain and code you cannot.
Procedures and functions
A subroutine is a named block of code that can be called from elsewhere in a program. AQA distinguishes two kinds.
A procedure carries out a task and does not return a value.
SUBROUTINE greet(name)
OUTPUT 'Hello ' + name
ENDSUBROUTINE
greet('Amira')A function carries out a calculation and returns a value, which the calling code then uses.
SUBROUTINE area(width, height)
RETURN width * height
ENDSUBROUTINE
size ← area(4, 7)The difference is exactly that: a function has a RETURN and its call appears where a value is expected. A procedure is called as a statement on its own.
Parameters and arguments
A parameter is the name in the subroutine definition. An argument is the actual value passed in when it is called. In the example above, width and height are parameters and 4 and 7 are arguments.
Parameters are what make a subroutine reusable. A subroutine that always calculates the area of a four by seven rectangle is useless. One that takes any two numbers can be called anywhere.
- Define it once with def, naming the parameters it will be given.
- Call it with arguments. They fill the parameters, w = 3 and h = 4.
- return hands the result back to the line that called it.
- A procedure does a job. A function also gives a value back.
Scope
The scope of a variable is the region of the program in which it can be accessed.
A local variable is declared inside a subroutine and exists only while that subroutine is running. A global variable is declared outside every subroutine and can be accessed anywhere.
SUBROUTINE tally()
count ← 0
count ← count + 1
RETURN count
ENDSUBROUTINEcount here is local. It is created when the subroutine starts and destroyed when it ends, so the subroutine returns 1 every single time it is called.
Why local variables are the better default
- No accidental interference. Two subroutines can each have a variable called
iwithout either affecting the other. - Memory is reclaimed. A local variable stops using memory as soon as the subroutine ends.
- The subroutine is self contained. Everything it needs comes in as a parameter and everything it produces comes back as a return value, so it can be moved, tested and reused without dragging the rest of the program along with it.
They are the right answer when genuinely many parts of the program need one shared value, such as a running total in a game. What makes them dangerous is that any subroutine can change one, so a bug can be caused from anywhere in the program.
- The program is the house. A variable made in the hallway is global, and any function can read it.
- Each function is a room. Variables made inside it are local and live only in that room.
- Outside code cannot see a room's local variables: asking for one gives a NameError.
Structured programming
Structured programming means building a program from separate, named, self contained subroutines with clearly defined inputs and outputs, rather than as one long block.
The advantages come up in exams constantly, and they are worth learning as reasons rather than as a list.
It is easier to write. Decomposing the problem gives you a set of small tasks, each of which is achievable. Two people can work on different subroutines at the same time without colliding.
It is easier to test. A subroutine with defined inputs and one output can be tested on its own with a handful of values. A tangled program can only be tested as a whole, which means a fault could be anywhere.
It is easier to maintain. A change to how VAT is calculated means editing one subroutine, not searching a thousand lines. Because the subroutine is self contained, you can be confident the change has not broken something elsewhere.
Code can be reused. A validation subroutine written once can be called from every point in the program that needs it, and reused in the next program entirely.
It is easier to read. A main program that reads loadQuestions(), askQuestion(), updateScore() explains itself. The same logic written inline does not.
"It is easier to maintain" is one mark at best. "It is easier to maintain, because a change only has to be made in the one subroutine responsible for that task rather than in every place the code was repeated" is the full answer.
Key terms you must be able to define
- Subroutine
- A named block of code that can be called from elsewhere in a program.
- Procedure
- A subroutine that performs a task and does not return a value.
- Function
- A subroutine that performs a calculation and returns a value to the code that called it.
- Parameter
- A named value in a subroutine definition that receives an argument when the subroutine is called.
- Argument
- The actual value passed to a subroutine when it is called.
- Return value
- The value a function sends back to the code that called it.
- Scope
- The region of a program in which a variable can be accessed.
- Local variable
- A variable declared inside a subroutine, which exists only while that subroutine runs.
- Global variable
- A variable declared outside all subroutines, accessible anywhere in the program.
- Structured programming
- Building a program from separate, self contained subroutines with defined inputs and outputs.
Flashcards
Say the definition out loud before you flip the card. Retrieving it from memory is what builds recall, reading it again is not.
Reach the top grade on this topic
There are two things that separate a full mark answer here.
Naming the direction of data. A parameter carries data in. A return value carries data out. An answer that says which is which, and names the actual values in the question, is complete.
Explaining scope as a consequence rather than a rule. "Local variables cannot be accessed outside the subroutine" is the rule. "Which means two subroutines can each use a variable called total without one overwriting the other" is the reason it is worth having, and that is what a high mark answer says.
Mistakes that cost marks here
- Calling every subroutine a function. A function returns a value, a procedure does not.
- Mixing up parameter and argument. The parameter is in the definition, the argument is the value passed in.
- Saying a local variable is 'deleted' when the program ends. It ends when the subroutine ends, not the program.
- Listing the advantages of structured programming without giving a reason for any of them.
- Assuming global variables are always bad practice. They are appropriate for genuinely shared state and dangerous only because any part of the program can change one.
The word 'bug' predates computing, but the most famous one is real. In 1947 a moth was found stuck in a relay of the Harvard Mark II, and the operators taped it into the logbook with the note 'first actual case of bug being found'.
Knowledge check
Exam-style questions
Five written questions in the style of the real paper. Write a full answer, then let the marker check it against the mark scheme.
- LA parameter is the name given in the subroutine definition
- LAn argument is the actual value passed in when the subroutine is called
A parameter is the named variable listed in the subroutine's definition, which receives a value when the subroutine runs. An argument is the actual value supplied at the point where the subroutine is called.
- LA local variable exists only while the subroutine runs
- LSo it cannot be changed by any other part of the program
- LTwo subroutines can use the same variable name without conflict
- LThe subroutine becomes self contained, so it is easier to test and reuse
A local variable is created when the subroutine starts and destroyed when it finishes, so it cannot be read or altered by any other part of the program. That removes a whole class of bug in which one section of a program changes a value another section was relying on, and it means two subroutines can each use a variable called total without either affecting the other. It also makes the subroutine self contained: everything it needs arrives as a parameter and everything it produces leaves as a return value, so it can be tested on its own and reused in another program without dragging the rest of the code along with it.
- LCode written once can be called from several places, so there is less repetition
- LA change or correction only has to be made in one place
- LEach subroutine can be tested independently
- LThe program is easier to read and several people can work on it at once
The first advantage is maintenance. A task written once as a subroutine is called wherever it is needed, so there is no repeated code, and when that task has to change it is corrected in exactly one place rather than in every copy. The second is testing and readability. Each subroutine has one clear job and defined inputs and outputs, so it can be tested on its own with a small set of values before it is trusted, and the main program reads as a list of named steps, which makes it far easier for another programmer, or for you in six months, to follow.
- LThe counter is declared as a local variable inside the subroutine
- LIt is therefore created again each time the subroutine is called
- LThe value from the previous call is lost when the subroutine ends
- LCorrect it by making the counter global, or by passing the count in and returning it
The counter has been declared and initialised inside the subroutine, which makes it local. A local variable is created when the subroutine starts and destroyed when it ends, so the value reached on one call is gone by the next and the counter is reset to zero every time, which is why it always returns one. There are two reasonable corrections. Declaring the counter as a global variable outside every subroutine means it persists between calls. Alternatively, and more safely, the current count can be passed in as a parameter and the new count returned, which keeps the subroutine self contained.