AS & A Level Computer Science · Area 2 · A Level content

Programming paradigms, file processing and exception handling

Four paradigms and two practical skills sit in this section, and the marks are lost in predictable places. Students define a paradigm as though it were a language, describe immediate addressing as though the operand were an address, and confuse inheritance with containment. In the file questions the errors are mechanical: the wrong open mode, a read before the EOF test, or no exception handling around the open. Treat each paradigm as a set of characteristics to compare, and each file operation as a fixed order of statements.

Not started

Syllabus coverage

  • Understand what is meant by a programming paradigm
  • Show understanding of the characteristics of low-level programming, and write low-level code that uses immediate, direct, indirect, indexed and relative addressing modes
  • Show understanding of the characteristics of imperative (procedural) programming, including structural programming (AS content, section 11.3)
  • Write imperative (procedural) code that uses variables, constructs, procedures and functions
  • Show understanding of the terminology associated with OOP, including objects, properties/attributes, methods, classes, inheritance, polymorphism, containment (aggregation), encapsulation, getters, setters and instances
  • Show understanding of how to solve a problem by designing appropriate classes
  • Show understanding of, and write code that demonstrates the use of, object-oriented programming
  • Show understanding of the characteristics of declarative programming
  • Solve a problem by writing appropriate facts and rules based on supplied information
  • Write code that can satisfy a goal using facts and rules
  • Write code to perform file-processing operations: open a file in read, write and append mode, and close a file
  • Read a record from a file and write a record to a file
  • Perform file-processing operations on serial, sequential and random files
  • Show understanding of an exception and the importance of exception handling, know when it is appropriate, and write program code that uses it

Part of the AS & A Level Computer Science syllabus 9618.

What a paradigm is, and the four in this syllabus

A programming paradigm is a style or approach to writing programs: the set of features a language offers and the way those features are used to break a problem down. It is not the same thing as a language and not the same thing as a program. One language can support more than one paradigm - Python can be written as a procedural program or as an object-oriented one - and the same problem can be solved in any of them.

Paradigms are grouped in two ways. By level, a paradigm is either low-level, where the instructions map closely onto the machine's own operations, or high-level, where the instructions are closer to the problem. By what the programmer writes, a paradigm is either imperative, where the programmer states the steps that must be carried out and the order they go in, or declarative, where the programmer states facts and rules and leaves the order of execution to the system. Low-level, imperative and object-oriented programming are all imperative; declarative programming is not.

The distinction that earns marks is how against what. In an imperative program you write the steps: set a total to zero, add each mark, divide by the count. In a declarative program you write what is true and what must be satisfied, and the system works out how to satisfy it. Object-oriented programming is still imperative, but it organises the imperative steps around the data they act on, which is what makes it a separate paradigm rather than a tidier version of the procedural one.

The syllabus asks for characteristics, not history. For each paradigm be ready to say what the programmer writes, what the language provides, what the paradigm is good at, where it is weak, and one situation in which you would choose it. That five-sentence shape answers almost every question on this section.

  • Low-level: instructions close to machine code, direct control of registers and memory, machine dependent; fast and compact, but slow and difficult to write.
  • Imperative (procedural): sequence, selection and iteration acting on variables, grouped into procedures and functions; the programmer states the steps, the how.
  • Object-oriented: imperative code organised into classes and objects, with encapsulation, inheritance and polymorphism.
  • Declarative: facts and rules, and a goal to satisfy; the system decides the order in which they are applied, the what.
  • A paradigm is not a language: one language can support several paradigms, and the same problem can be written in any of them.
  • A paradigm is not a program: it is a way of thinking about a solution, not a particular solution.
ParadigmWhat the programmer writesBuilt aroundTypical use
Low-levelInstructions that name registers, memory addresses and addressing modesThe processor and its instruction setDevice drivers, embedded controllers, code where speed, size or timing is critical
Imperative (procedural)A sequence of statements using sequence, selection and iteration, grouped into procedures and functionsVariables, assignment and subroutinesGeneral-purpose programs: calculations, file processing, simulations
Object-orientedClasses that define attributes and methods, then objects created from themObjects that hold both data and the methods that act on that dataLarge programs with many related kinds of data: booking systems, games, user interfaces
DeclarativeFacts and rules, and a goal to satisfyThe relationships described by the facts and rulesRule-based reasoning, expert systems, database queries
A question that asks you to compare paradigms wants a difference in what the programmer writes, not a list of language names. 'In an imperative program the programmer writes the order of the steps, whereas in a declarative program the programmer writes facts and rules and the system chooses the order' is a comparison; 'Python is imperative and Prolog is declarative' is not.

Low-level programming: mnemonics, registers and the machine

Low-level programming means writing instructions that correspond closely to the operations the processor itself performs. Each instruction is a single machine operation - load a value, add, store, compare, jump - written as a mnemonic with an operand, such as LDD 400 or ADD #5. An assembler translates each mnemonic into one machine code instruction, so the programmer works at the level of the machine rather than at the level of the problem.

The programmer has to do explicitly everything a high-level language does quietly: move values between memory and the accumulator (ACC), use the index register (IX) to work through a table, choose an addressing mode for every operand, and control the order of execution with jumps. Cambridge assembly questions assume a single general-purpose register, the accumulator, so almost every instruction is written around getting the right value into ACC, doing something to it, and storing it back.

That control is why low-level code still exists. It produces compact, fast code, it can reach hardware that a high-level language cannot name, and its timing is predictable, which matters in a device driver, an interrupt handler, a boot loader or the firmware of an embedded controller. It is also machine dependent: the instruction set belongs to one family of processors, so the program will not run on a different processor without being rewritten.

The cost is the programmer's time. Low-level code is long, hard to read, hard to debug and hard to maintain, because a page of it may do no more than add ten numbers. That is why high-level languages exist, and why you are asked to write and trace small low-level routines rather than to build whole systems in assembly.

  • One mnemonic maps to one machine instruction: LDM #25 puts the number 25 into the accumulator.
  • Registers and memory are named directly. Only ACC and IX are available, so values must be moved into them and stored back out.
  • The addressing mode of every operand has to be chosen by the programmer, because the machine has no idea what the operand is meant to be.
  • Machine dependent: the instruction set and the addresses belong to one processor family, so the code is not portable.
  • Strengths: very fast, very compact, precise control of hardware and timing.
  • Weaknesses: slow to write, hard to read and maintain, easy to get wrong, and no built-in structures such as arrays or records.
Instruction groupExamplesWhat it does
Data movementLDM #n, LDD address, LDI address, LDX address, LDR #n, STO address, MOV IXLoads a value into ACC or IX, or stores the contents of ACC into memory
ArithmeticADD #n, ADD address, SUB #n, SUB address, INC IX, DEC IXAdds to, subtracts from or adjusts the value held in a register
Comparison and branchingCMP #n, CMP address, JPE address, JPN address, JMP addressCompares ACC with a value, then jumps unconditionally or according to the result
Input and outputIN, OUTReads a character into ACC, or outputs the character whose ASCII value is in ACC
Ending the programENDReturns control to the operating system
Write the addressing mode into the instruction you choose, not into a comment. LDM #25 is immediate and LDD 400 is direct; an answer that says 'load 400' without saying whether 400 is the value or the address has described nothing.

Addressing modes: immediate, direct, indirect, indexed and relative

An addressing mode is the rule for interpreting the operand of an instruction. The operand field of a machine instruction is only a few bits wide, far too short to hold a full memory address or a large number, so the processor provides several modes that let a short operand reach any data it needs.

Immediate addressing puts the value itself in the operand: LDM #25 loads the number 25 into ACC, and the # shows that 25 is a value, not an address. It is the fastest mode, because no memory access is needed to fetch the operand, but the value is fixed when the program is written.

Direct addressing puts the address of the value in the operand: LDD 400 loads into ACC the contents of memory location 400. One extra memory access is needed and the instruction can only reach addresses that fit the operand field, but the contents of that address can change while the program runs, which is why direct addressing is used for variables.

Indirect addressing puts the address of an address in the operand: LDI 400 looks at location 400, finds an address stored there, and loads the contents of that second address into ACC. Two memory accesses are needed, but the operand does not have to hold the final address, so the program can reach anywhere in memory and can change its target by changing the pointer. This is how pointers, linked structures and passing parameters by reference are implemented.

Indexed addressing forms the address at run time by adding the contents of the index register to the address in the operand. If IX holds 6, LDX 400 loads the contents of address 406. The index register can be incremented on each pass of a loop, so one instruction walks through an array or a table, which is how arrays are handled in assembly language.

Relative addressing treats the operand as a displacement from the address of the current instruction rather than as an absolute address. A relative jump such as JMP +3 passes control to the instruction three places on from the present one, and the processor calculates the target by adding the displacement to the program counter. Because the operand is a distance rather than a fixed address, the code works wherever it is loaded in memory, which is what makes relocatable routines possible.

ModeWhat the operand isExampleWhat reaches ACCWhy it is used
ImmediateThe value itselfLDM #2525Fast, no memory access for the operand; used for constants
DirectThe address of the valueLDD 400The contents of address 400A variable held at a known address
IndirectThe address of a location that holds the addressLDI 400, where location 400 holds 900The contents of address 900Pointers; the target can be changed while the program runs
IndexedA base address, with the contents of IX addedLDX 400 with IX = 6The contents of address 406Arrays and tables; one instruction walks a list
RelativeA displacement from the current addressJMP +3Control passes three instructions forwardJumps in code that may be moved in memory
Direct and indirect differ by one memory access, and that difference is the mark. In direct addressing the operand is the address of the data; in indirect addressing the operand is the address of a location that holds the address of the data.

Imperative (procedural) programming and structured programming

Imperative programming is programming as a list of commands that change the state of the program. The program has variables, each holding a value, and each statement assigns a value, reads a value or decides what happens next. Procedural programming is imperative programming organised into procedures and functions: named blocks of code that can be called, can be given parameters and, in the case of a function, return a value.

Everything in the paradigm is built from three constructs. Sequence is one statement after another in the order written. Selection chooses between paths with IF ... THEN ... ELSE ... ENDIF or CASE ... OF ... ENDCASE. Iteration repeats a block with FOR ... NEXT, WHILE ... ENDWHILE or REPEAT ... UNTIL. A program of any size is these three constructs nested inside one another, plus subroutines.

Structured programming - called structural programming in the syllabus - is the discipline that keeps that nesting under control, and it is assumed knowledge from AS section 11.3. The program is designed top-down and broken into subroutines that each do one job; each subroutine has one entry point and one exit point; there is no GOTO, so control never jumps into the middle of a block; and the code is indented and named so that its structure can be read. Structured code is easier to test, because each subroutine can be tested alone, and easier to maintain, because a change is confined to the subroutine responsible for that job.

Procedures and functions are what make the paradigm scale. A procedure carries out an action and may change the values passed to it; a function returns a single value and can be used inside an expression. Parameters are passed by value, which copies the value so the original is untouched, or by reference, which passes the address so the subroutine can change the caller's variable. Variables declared inside a subroutine are local and cease to exist when it ends; variables declared outside are global and can be read and changed by any subroutine, which is convenient and dangerous in equal measure.

The weakness is the separation of code and data. The data of a program - a pupil, an order, an account - is spread across variables and arrays, and every procedure that touches it must know how it is stored. Change the layout of the data and every procedure that uses it has to change too, and nothing stops one procedure from writing nonsense into another's data by mistake. Object-oriented programming is the answer to exactly that problem.

  • Sequence, selection and iteration are the only control constructs; every program is built from them.
  • A procedure performs an action; a function returns a value.
  • Parameters pass data in. By value copies the value; by reference passes its address, so the subroutine can change the caller's variable.
  • Local variables exist only inside their subroutine; global variables are visible everywhere and are a common source of bugs.
  • Structured programming: top-down design, one entry and one exit per subroutine, no GOTO, clear indentation and meaningful names.
  • Strength: it matches the way a processor works, so it is natural to trace, test and translate.
  • Weakness: data and the code that uses it are separate, so large programs become hard to maintain and hard to reuse.
ConstructKeywords in pseudocodeWhen it is used
SequenceStatements one after anotherAlways - it is the default order of execution
SelectionIF ... THEN ... ELSE ... ENDIF, CASE ... OF ... ENDCASEWhen one of several paths must be chosen
Iteration, count-controlledFOR ... TO ... NEXTWhen the number of repetitions is known in advance
Iteration, condition-controlledWHILE ... DO ... ENDWHILE, REPEAT ... UNTILWhen repetition depends on a condition
SubroutinePROCEDURE ... ENDPROCEDURE, FUNCTION ... ENDFUNCTIONWhen a block of code does one job and is used more than once
When a question asks for the characteristics of procedural programming, name the constructs, the variables, the subroutines and the top-down structure. 'It uses functions' on its own is a feature of almost every paradigm and scores nothing.

Object-oriented programming: classes, objects and encapsulation

Object-oriented programming (OOP) keeps the imperative constructs but changes what the program is built from. Instead of separate variables and procedures, a program is built from objects, and each object holds both its own data and the methods that act on that data. A class is the template describing what objects of that kind contain: its attributes (also called properties) and its methods. An object is an instance of a class, created while the program runs, with its own copy of the attributes.

A class is designed by looking at the problem for nouns and verbs. A booking system mentions customer, room and booking, so those become classes; a customer has a name and a telephone number, so those become attributes; a customer can be created, changed and checked in, so those become methods. Attributes are usually declared private and methods public, and the public methods that read and write a single attribute are its getters and setters. A getter returns the value of an attribute; a setter takes a new value, checks it and stores it.

Encapsulation is the combining of data and the methods that operate on it inside one class, together with the hiding of that data behind the methods. Because the attributes are private, no other part of the program can assign to them directly: it must call a setter, and the setter can reject a negative balance or a blank name. The object protects its own data, and it can be changed internally later without breaking the code that uses it, provided the public methods keep the same parameters.

Inheritance lets a new class be defined from an existing one. The subclass inherits the attributes and methods of the superclass, can add its own, and can override an inherited method with a version that behaves differently. Inheritance models an is-a relationship: a SavingsAccount is a BankAccount, so it can be used wherever a BankAccount is expected. Containment (aggregation) is different and is often confused with it: an object holds another object as one of its attributes, modelling a has-a relationship - a Car has an Engine, a Booking has a Room.

Polymorphism means that the same method call can behave differently for different objects. If BankAccount has a method CalculateInterest and SavingsAccount overrides it, calling CalculateInterest on a variable declared as BankAccount runs the version belonging to the object actually stored there. The calling code does not need to know which subclass it has, which is what lets a program hold a mixture of related objects in one array and process them in a single loop.

TermMeaningExample
ClassThe template that defines the attributes and methods of a type of objectCLASS BankAccount ... ENDCLASS
Object (instance)One item created from a class, with its own values for the attributesAccount1 <- NEW BankAccount("A. Patel", 50.00)
Attribute (property)A piece of data held by each object of the classOwnerName : STRING, Balance : REAL
MethodA subroutine that defines what an object can doDeposit(Amount), GetBalance()
GetterA public method that returns the value of a private attribute without changing itGetBalance() RETURNS REAL
SetterA public method that validates a new value and stores it in a private attributeSetOwnerName(Name : STRING)
EncapsulationCombining data and methods in one class and hiding the data behind the methodsPrivate attributes reached only through getters and setters
InheritanceA subclass takes the attributes and methods of a superclass and may add to or override themCLASS SavingsAccount INHERITS BankAccount
PolymorphismThe same method call behaves according to the actual class of the objectCalculateInterest() runs the subclass version for a savings account
Containment (aggregation)An object holds another object as one of its attributes, a has-a relationshipA Booking has a Room; a Car has an Engine
Inheritance is is-a; containment is has-a. 'A car has an engine' is containment, 'a savings account is a bank account' is inheritance, and candidates who write the wrong one lose the mark even when they can define both.

Designing classes and writing object-oriented code

A question that asks you to design appropriate classes wants four things: the class names, their attributes with data types, their methods with parameters, and the relationships between them. Work from the scenario, not from a memorised list. Each noun the scenario stores data about is a class, each item of data it mentions is an attribute, each action it describes is a method, 'is a' between two nouns means inheritance and 'has a' means containment.

The class below shows the pattern. The attributes are private, the constructor and the methods are public, and the getter and setter are the only route to the balance. Deposit validates its parameter, and that check exists only because the balance cannot be changed from outside the class - encapsulation doing real work rather than being a definition to recite.

Inheritance and containment are chosen from the scenario. If the new class is a special case of an existing one that shares nearly all its attributes and methods, inherit: a SavingsAccount needs everything a BankAccount has, plus an interest rate. If the new class merely uses another object, contain it: a Booking is not a Room, it holds one. Inheriting when you should contain produces a class that drags round attributes it does not need and breaks when the superclass changes.

Write the code the way the marks are awarded: declare the class, declare its attributes with types, declare its methods with parameters, and use the object only through its public methods. A design with no methods, or with every attribute public, loses the marks for encapsulation and for the behaviour the scenario described.

Line of pseudocodeWhat it shows
CLASS BankAccountDeclares the class: the template for every account object
PRIVATE OwnerName : STRINGA private attribute, hidden from the rest of the program
PRIVATE Balance : REALA second attribute; each object gets its own copy of both
PUBLIC PROCEDURE New(Owner : STRING, Opening : REAL)A constructor: creates an instance and sets its initial state
Balance <- OpeningAssignment to the object's own attribute
PUBLIC FUNCTION GetBalance() RETURNS REALA getter: returns the attribute without allowing it to be changed
PUBLIC PROCEDURE Deposit(Amount : REAL)A method that changes the state of the object
IF Amount > 0 THEN Balance <- Balance + Amount ENDIFValidation inside the class, which encapsulation makes possible
ENDCLASSEnds the class definition; no object exists yet
Account1 <- NEW BankAccount("A. Patel", 50.00)Creates one instance of the class
OUTPUT Account1.GetBalance()Calls a method on that object using dot notation
CLASS SavingsAccount INHERITS BankAccountA subclass that inherits the attributes and methods of the superclass
PUBLIC PROCEDURE AddInterest()A method that exists only in the subclass, after the interest rate is added as an attribute
PUBLIC PROCEDURE Deposit(Amount : REAL)The subclass declares Deposit again, overriding the inherited version
Design from the nouns and the verbs. 'Room, Booking and Customer, each with its attributes and methods, and a Booking has a Room' is a design; a list of words followed by the sentence 'it uses inheritance' is not.

Declarative programming: facts, rules and goals

Declarative programming describes what is true rather than what to do. A declarative program is a set of facts and rules, and it is used by putting a goal to it - a question - which the system tries to satisfy by applying the facts and rules. There is no assignment, no loop and no sequence of statements to follow: the programmer supplies the knowledge and the system works out the order in which to use it.

A fact is a statement that is unconditionally true, written as a relation with its arguments. In Prolog, parent(tom, bob). states that tom is a parent of bob, and female(ann). states that ann is female. Lower-case words are atoms - fixed names - and a name beginning with a capital letter is a variable, which can stand for anything.

A rule states something that is true provided other things are true. It has a head and a body, and the body is a list of conditions that must all hold. In pseudocode the rule is written grandparent(X, Z) IF parent(X, Y) AND parent(Y, Z); in Prolog the same rule is written grandparent(X, Z) :- parent(X, Y), parent(Y, Z), where :- is read as 'if' and the comma as 'and'. This says that X is a grandparent of Z if there is some Y such that X is a parent of Y and Y is a parent of Z. The variable Y is the link between the two conditions, so one rule answers the question for every family in the facts.

A goal is the question put to the program, such as grandparent(tom, Who). The system matches the goal against the head of a fact or rule, binding variables as it goes (unification); if a condition in the body cannot be satisfied it backtracks to the last choice it made and tries the next possibility, and it continues until it has found every solution or exhausted the possibilities. That search is the 'how', and the programmer never writes it.

The paradigm suits problems that are naturally a set of relationships or rules: family relationships, a diagnostic or advisory expert system that reasons from symptoms to a conclusion, a timetable or route that must satisfy constraints, and a database query. It is poor at problems that are a sequence of actions with input and output, such as a game loop or a user interface, and a badly written set of rules can make the search very slow.

  • Fact: unconditionally true, for example parent(tom, bob).
  • Rule: true if its body is true, for example grandparent(X, Z) IF parent(X, Y) AND parent(Y, Z), written in Prolog as grandparent(X, Z) :- parent(X, Y), parent(Y, Z).
  • Goal: the question asked of the program, for example grandparent(tom, Who).
  • Variable: a name beginning with a capital letter, bound to different values during matching.
  • Backtracking: when a condition fails, the system returns to the last choice and tries the next possibility.
  • Recursion replaces iteration, as in ancestor(X, Y) IF parent(X, Y) together with ancestor(X, Z) IF parent(X, Y) AND ancestor(Y, Z).
  • Strength: concise, easy to extend with new facts, and the knowledge is kept separate from the search.
  • Weakness: no natural input, output or sequence; the search can be slow; the programmer has less control over how the answer is found.
Part of the programWhat it isExample
FactA statement that is always trueparent(tom, bob).
Rule headThe conclusion the rule provesgrandparent(X, Z)
Rule bodyThe conditions that must all be trueparent(X, Y) AND parent(Y, Z)
GoalThe question the user asksgrandparent(tom, Who)
VariableA placeholder bound during matchingX, Y, Z, Who
A fact has no conditions; a rule has a body. An answer made up only of statements such as parent(tom, bob). contains facts but no rules, and the marks for rules are lost.

File processing: modes, records and the three file organisations

A program that keeps its data only in variables loses it when it ends, so data that must survive is written to a file on secondary storage. Every file operation follows the same pattern: open the file in the right mode, read or write records, then close it, because closing flushes any buffered data to the disk and releases the file.

The mode is chosen from what the program is about to do. FOR READ opens an existing file so that data can be read and nothing written. FOR WRITE creates a new file, or empties an existing one, and is used when the whole file is being produced from scratch - it destroys whatever was there. FOR APPEND opens an existing file and positions the write after the last record, which is how records are added without losing the others. FOR RANDOM opens a file of fixed-length records for direct access, so that a record can be read or replaced by its position.

A record is one complete item in the file - one pupil, one order, one booking - held as a set of fields of different types. In a text file a record is normally one line, so reading a record means reading a line with READFILE and splitting it into its fields, and writing a record means joining the fields into a line and using WRITEFILE. In a random file the record is written whole with PUTRECORD and read whole with GETRECORD into a variable of the record type.

A serial file holds records in the order they were added, with no ordering by any key; to find one record you must read from the beginning, so it is used where every record is processed anyway, such as a transaction log or a backup. A sequential file holds records in order of a key field, such as a pupil number or an account number, and is read in that order; a record is found by reading through until the key matches, and adding or deleting one in the middle means rewriting the file, which is why sequential files are updated in a batch by merging an old master file with a transaction file to produce a new master file. A random file holds fixed-length records at known positions, so SEEK moves the file pointer straight to a record and GETRECORD or PUTRECORD reads or writes it without touching the records before it, which makes random files fast for looking up and updating individual records.

Choose by how the data will be used. If every record is processed in one run and the order does not matter, serial is enough. If the data must be processed in key order, sequential is right - payroll, billing and end-of-term reports are all like this, and sequential files suit magnetic tape because tape can only be read in order. If individual records must be found and changed quickly, random is right, but all the records must be the same length and there must be a way to calculate the address from the key.

  • Open modes: READ for an existing file, WRITE to create or empty a file, APPEND to add at the end without losing what is there, RANDOM for fixed-length records and direct access.
  • Read a text file: OPENFILE ... FOR READ, WHILE NOT EOF(...) DO, READFILE one line, process it, ENDWHILE, CLOSEFILE.
  • Add a record without destroying the others: open FOR APPEND and write one record; FOR WRITE would empty the file first.
  • Update a random file: open FOR RANDOM, SEEK the position, GETRECORD, change the fields, SEEK the same position again, PUTRECORD, close.
  • Serial: order added, sequential access only, every record processed - a transaction log or a backup.
  • Sequential: ordered by a key field, read in key order, updated in a batch by merging a master file with a transaction file.
  • Random: fixed-length records at calculated positions, reached directly with SEEK - fast lookup and update of single records.
  • Close every file: CLOSEFILE flushes buffered records to disk, and a program that forgets it can lose the last records it wrote.
StatementWhat it does
OPENFILE "pupils.txt" FOR READOpens an existing text file so that records can be read
OPENFILE "pupils.txt" FOR WRITECreates a new text file, or empties an existing one
OPENFILE "pupils.txt" FOR APPENDOpens a text file so that new records go after the last one
OPENFILE "pupils.dat" FOR RANDOMOpens a file of fixed-length records for direct access
READFILE "pupils.txt", LineOfTextReads the next line of a text file into a variable
WRITEFILE "pupils.txt", LineOfTextWrites one line to a text file
SEEK "pupils.dat", 10Moves the file pointer to record position 10
GETRECORD "pupils.dat", PupilReads the record at the pointer into a record variable
PUTRECORD "pupils.dat", PupilWrites the record variable at the pointer, replacing what was there
EOF("pupils.txt")TRUE once the whole file has been read
CLOSEFILE "pupils.txt"Flushes the file to disk and releases it
FOR WRITE empties the file; FOR APPEND keeps it. A file-processing answer that opens an existing file for writing destroys every record already stored, which is the most expensive mistake in this section.

Exceptions and exception handling

An exception is an error or unexpected event that happens while a program is running and that the normal flow of the program cannot deal with: a file that does not exist, a division by zero, text that cannot be converted into a number, an index outside the bounds of an array. It is detected by the system rather than by the program's own IF statements, and if nothing deals with it the program terminates at that point, losing whatever was in memory and showing the user an error message that means nothing to them.

Exception handling is the facility that lets a program say what to do when an exception occurs. The code that might fail goes in a TRY block and the code that deals with the failure goes in an EXCEPT block. If every statement in the TRY block runs without an exception, the EXCEPT block is skipped; if any statement in it raises an exception, the rest of the TRY block is abandoned and control passes straight to the EXCEPT block, after which the program continues with the statement after ENDTRY.

The importance of handling is in that last sentence. Without it, one bad record or one missing file ends the whole run. With it, the program can report the problem, use a default value, ask for another file name, write the record to a reject file, or close the files it has open and stop cleanly - and it can do so in one place instead of after every statement. Handling also keeps the main logic readable, because checks for things that should never happen are separated from the code that does the work.

Use exception handling where the failure is outside the program's control and cannot be ruled out in advance: opening a file that may not exist or may be locked, reading past the end of a file, converting text typed by a user into a number, dividing by a value that might be zero, and any input from a network or a device. Do not use it in place of validation where the error is predictable - a mark out of 100 should be checked with an IF statement, because that is ordinary data handling and the check belongs in the logic. The rule of thumb is that validation deals with input that is wrong, and exception handling deals with a situation the program could not prevent.

The block below is the pattern to write in an exam. The TRY block contains the whole file operation, including the close, so that a failure at any point is caught, and the EXCEPT block reports the problem in words the user can act on. In a real language the block looks the same with different keywords: Java uses try and catch, and Python uses try and except.

Line of pseudocodeWhat it does
TRYStarts the block of code that might raise an exception
OPENFILE "pupils.txt" FOR READThe operation most likely to fail, because the file may not exist
WHILE NOT EOF("pupils.txt") DO ... ENDWHILEThe normal processing, kept inside the protected block
READFILE "pupils.txt", LineOfTextReads each record; this too can fail, for example on a damaged file
CLOSEFILE "pupils.txt"Closing inside the block, so the file is released on the normal path
EXCEPTRuns only if a statement in the TRY block raised an exception
OUTPUT "The file could not be opened or read."The recovery: tell the user in words they can act on
ENDTRYEnds the block; the program continues after this line
Exception handling does not stop the error happening; it stops the program dying. Always say what the program does after the exception - report it, use a default, close the file, ask again. An EXCEPT block that only prints 'error' earns very little.

Key terms you must be able to define

Programming paradigm
A style or approach to writing programs, defined by the features a language provides and the way a problem is broken down. It is not the same thing as a language, because one language can support several paradigms.
Low-level programming
Programming with instructions that correspond closely to the processor's own machine operations, naming registers, memory addresses and addressing modes. An assembler translates each mnemonic into one machine code instruction, and the code is machine dependent.
Addressing mode
The rule that decides how the operand of an instruction is interpreted: whether it is the value itself, the address of the value, or something from which the address is calculated. The five in this syllabus are immediate, direct, indirect, indexed and relative.
Imperative (procedural) programming
A paradigm in which the programmer writes the steps that change the state of the program, using sequence, selection and iteration on variables, with procedures and functions to group the steps into named blocks.
Structured programming
The discipline of building a program from sequence, selection and iteration only, designed top-down into subroutines that each have one entry and one exit, with no GOTO, so that the structure of the code is visible and each part can be tested on its own.
Class
The template that defines the attributes and the methods that objects of that type will have. It describes the objects; it is not itself an object, and no storage is created until an instance is made.
Object (instance)
One item created from a class while the program runs, with its own copy of the attributes and access to the methods defined by the class.
Encapsulation
The combining of data and the methods that operate on it inside one class, together with the hiding of the data behind those methods, so that attributes can only be read and changed through public getters and setters that can validate the change.
Inheritance
The mechanism by which a subclass takes the attributes and methods of a superclass, may add its own, and may override an inherited method. It models an is-a relationship, such as a savings account being a kind of bank account, and it promotes reuse of tested code.
Polymorphism
The property that the same method call behaves differently according to the actual class of the object it is made on, so code can process a mixture of related objects in one loop without knowing which subclass each one belongs to.
Containment (aggregation)
A relationship in which an object holds another object as one of its attributes, modelling a has-a relationship, such as a booking holding a room. It is not inheritance, which models is-a.
Declarative programming
A paradigm in which the programmer writes facts and rules that describe what is true, and puts a goal to the system, which works out the order in which to apply the facts and rules. There is no assignment and no explicit loop or sequence.
Serial, sequential and random files
Three ways of organising a file. Serial: records in the order they were added, read sequentially from the start. Sequential: records in order of a key field, read in that order and updated in a batch. Random: fixed-length records at positions calculated from the key, reached directly with SEEK and GETRECORD or PUTRECORD.
Exception handling
The facility that lets a program respond to a run-time error instead of terminating. The code that may fail is placed in a TRY block and the recovery in an EXCEPT block, so the program can report the problem, recover and carry on.

Applied to real systems

9618 sets its questions inside systems you already use - a phone, a school network, a supermarket till, a website, a bank. These show how to apply the theory to a context you have not seen before, then you write your own.

Low-level code: the firmware of an embedded controller

A microcontroller inside a washing machine or a car's engine management unit has to read a sensor at a fixed, memory-mapped address and respond within a guaranteed number of clock cycles. That code is written in assembly: LDD reads the sensor's address directly, LDX with the index register steps through a table of settings, and immediate loads put constants into the accumulator. A high-level language would hide the exact addresses and the exact timing, which is precisely what this code cannot allow, and the same program will not run on a different processor family without being rewritten. It is the clearest case of a situation where low-level control matters more than the programmer's time.

Object-oriented design: a bank account class hierarchy

A banking system holds each account as an object of class BankAccount, with OwnerName and Balance private and Deposit, Withdraw and GetBalance public, so the balance can only change through code that checks the amount. SavingsAccount inherits from it, adds an interest rate and overrides CalculateInterest, while CurrentAccount inherits too, adds an overdraft limit and overrides Withdraw so that a withdrawal past the limit is refused. One array of BankAccount can hold both kinds, and a single loop calling CalculateInterest runs the right version for each object, which is polymorphism. Containment appears alongside inheritance: a Customer has an Address, and a Branch has a set of Accounts.

Declarative programming: a database query

A query such as SELECT Surname FROM Pupils WHERE YearGroup = 12 states what result is wanted and says nothing about how to get it; the database management system's query optimiser decides whether to scan the table or to use an index. This is the same division of labour as a Prolog goal: the programmer supplies the facts, in the form of tables, and the condition, in the form of the query, and the system chooses the order of the search. It is the everyday example of declarative programming, and a good contrast with a procedural loop that reads every pupil record and tests the year group itself.

File processing: a payroll batch run on sequential files

A payroll system keeps a master file sorted by employee number and, during the month, writes each change to a transaction file as it happens. At the end of the month a batch program reads both files in employee-number order, merges them, applies the changes and writes a new master file, passing through each sequential file once from beginning to end. This works because both files are in the same key order, so the program can process them side by side without searching, and the old master file is kept until the new one has been checked. It also shows the weakness of the organisation: one change cannot be made on its own, because the whole file has to be rewritten.

Exception handling: opening a data file that is not there

A program is asked to read yesterday's sales from sales.txt. If the file has been moved, renamed or never created, an unhandled exception stops the program dead and the user sees a system error message with no idea what to do about it. Wrapped in TRY ... EXCEPT ... ENDTRY, the same program reports that sales.txt could not be opened, offers to let the user choose another file or to carry on with an empty day, and closes anything it had already opened. The error still happened, but the program survived it and the user was told what to do next.

Flashcards

Click a card to flip it. Mark honestly — the tracker uses this.

Q1What is a programming paradigm, and which four does the syllabus require?
A style or approach to writing programs, defined by the features a language provides and the way a problem is broken down - not a language and not a program. The four are low-level, imperative (procedural), object-oriented and declarative. Low-level, imperative and object-oriented are all imperative, because the programmer writes the steps; declarative is not.
Q2Give five characteristics of low-level programming.
One mnemonic maps to one machine instruction, translated by an assembler. The programmer works directly with registers (ACC and IX), memory addresses and addressing modes. The code is machine dependent, so it is not portable between processors. It is fast, compact and gives precise control of hardware and timing, which is why it is used in device drivers, interrupt handlers and embedded firmware. It is slow to write, hard to read, hard to debug and has no built-in structures such as arrays or records.
Q3Name the five addressing modes and say what the operand means in each.
Immediate: the value itself (LDM #25 puts 25 in ACC). Direct: the address of the value (LDD 400 loads the contents of address 400). Indirect: the address of a location that holds the address (LDI 400 loads the contents of the address stored at 400). Indexed: a base address with the index register added (LDX 400 with IX = 6 loads address 406). Relative: a displacement from the current address, used for jumps in relocatable code.
Q4Why are indexed and relative addressing useful?
Indexed addressing forms the address at run time by adding IX to the operand, so incrementing IX once per loop makes a single instruction walk through an array or table - it is how arrays work in assembly. Relative addressing uses a displacement from the current instruction rather than an absolute address, so the code works wherever it is loaded in memory, which makes relocatable and position-independent routines possible.
Q5Give the characteristics of imperative (procedural) programming, including structured programming.
The programmer writes the steps that change the state of the program, using variables and assignment. Only three constructs are used: sequence, selection (IF, CASE) and iteration (FOR, WHILE, REPEAT), with procedures and functions holding reusable blocks, parameters passed by value or by reference, and local or global variables. Structured programming means top-down design, one entry and one exit per subroutine, no GOTO, and clear indentation and naming. The weakness is that data and code are separate, so large programs are hard to maintain and reuse.
Q6Define class, object, attribute, method, getter and setter.
A class is the template defining the attributes and methods of a type of object. An object, or instance, is one item created from a class at run time, with its own attribute values. An attribute (property) is a piece of data held by each object. A method is a subroutine defining what the object can do. A getter returns the value of a private attribute; a setter validates and stores a new value in one.
Q7What is encapsulation and why does it matter?
Combining data and the methods that operate on it in one class, and hiding the data behind those methods so that attributes are private and can only be read or changed through public getters and setters. It matters because the class can validate every change (rejecting a negative balance, for example), the object protects its own data from the rest of the program, and the internal implementation can change without breaking the code that uses the class.
Q8Distinguish inheritance, polymorphism and containment.
Inheritance is an is-a relationship: a subclass takes the attributes and methods of a superclass, may add its own and may override inherited methods (a SavingsAccount is a BankAccount). Polymorphism means the same method call behaves according to the object's actual class, so a mixture of related objects can be processed in one loop. Containment (aggregation) is a has-a relationship: an object holds another object as an attribute (a Booking has a Room, a Car has an Engine).
Q9In declarative programming, what are facts, rules and goals, and how is a goal satisfied?
A fact is unconditionally true, such as parent(tom, bob). A rule is true if its body is true, such as grandparent(X, Z) IF parent(X, Y) AND parent(Y, Z) in pseudocode, or grandparent(X, Z) :- parent(X, Y), parent(Y, Z) in Prolog, where capitalised names are variables that link the conditions. A goal is the question asked, such as grandparent(tom, Who). The system matches the goal against facts and rule heads, binding variables by unification, and backtracks to the last choice whenever a condition fails.
Q10Name the file open modes and the file commands, and give the pattern for reading a text file.
Modes: FOR READ (existing file), FOR WRITE (creates or empties), FOR APPEND (adds after the last record), FOR RANDOM (fixed-length records, direct access). Commands: OPENFILE, READFILE, WRITEFILE, CLOSEFILE, EOF, and for random files SEEK, GETRECORD and PUTRECORD. Pattern: open FOR READ, WHILE NOT EOF(file) DO, READFILE one line, process it, ENDWHILE, CLOSEFILE.
Q11Contrast serial, sequential and random files.
Serial: records in the order they were added, no key order, read from the start, used for transaction logs and backups. Sequential: records in order of a key field, read in that order through sequential access, updated in a batch by merging the master file with a transaction file. Random: fixed-length records at positions calculated from the key, reached directly with SEEK then GETRECORD or PUTRECORD, so individual records can be found and updated quickly, at the cost of fixed record lengths and wasted space.
Q12What is an exception, how is one handled in pseudocode, and when should handling be used?
An exception is an error or unexpected event raised while the program runs, such as a missing file, a division by zero or a value that cannot be converted to a number; unhandled, it terminates the program. Handling uses TRY (the code that may fail), EXCEPT (the recovery) and ENDTRY, and the program continues afterwards. Use it where the failure is outside the program's control - opening a file, converting user input, dividing by a value that might be zero - not instead of validation for input that can be checked with an IF statement.
0 of 12 marked as known

Exam-style questions

8 questions, 28 marks. Write your answer, then reveal the mark scheme and tick each point you actually made. Answering honestly here is what makes the rest of the site useful.

StateAO11 mark
State the addressing mode used by the instruction LDI 400.

Mark scheme — tick each point you actually made

Examiner tip: One mark, one term. LDI is the indirect load, so do not write direct because the operand looks like a plain address - the difference is that the address stored at 400 is used to find the data.
DefineAO12 marks
Define the term programming paradigm.

Mark scheme — tick each point you actually made

Examiner tip: Two halves: what it is, and the fact that it is a set of features or an approach rather than a particular language. 'Object-oriented programming' on its own is an example, not a definition.
ExplainAO23 marks
Explain three characteristics of low-level programming that make it suitable for writing a device driver.

Mark scheme — tick each point you actually made

Examiner tip: Each mark needs a characteristic and the reason it suits a device driver. 'It is low-level' or 'it is fast' without the link to controlling the hardware earns nothing.
ExplainAO23 marks
Explain the difference between direct, indirect and indexed addressing, with reference to the instructions LDD 400, LDI 400 and LDX 400.

Mark scheme — tick each point you actually made

Examiner tip: Every point must say what the operand is. The second mark usually needs the words 'the address of the address', and the third needs the calculation shown with a value in IX.
ExplainAO24 marks
A program is being written to manage a library, with classes for Book, Member and Loan. Explain how encapsulation and inheritance would be used in the design of these classes.

Mark scheme — tick each point you actually made

Examiner tip: Name the classes from the scenario in every point. A generic definition of encapsulation and a generic definition of inheritance scores at most half, because neither is applied to Book, Member or Loan.
WriteAO24 marks
A family tree is to be held in a declarative program. Write appropriate facts and rules that could be used to decide whether one person is an ancestor of another. Your answer should include at least one fact and at least one rule.

Mark scheme — tick each point you actually made

Examiner tip: A list of parent facts alone is not an answer to the question, because it contains no rule and therefore cannot reason. The recursive rule is the mark most often missed: it must call ancestor again, not parent. Either the IF/AND form or the Prolog :- and comma form is accepted, as long as the notation is used consistently.
WriteAO25 marks
The sequential file Stock.txt holds one line per product, with the fields ProductCode, Description and Price separated by commas. Write pseudocode to read every record, increase the price by 10 per cent and write the changed record to a new file NewStock.txt. The file Stock.txt may not exist.

Mark scheme — tick each point you actually made

Examiner tip: Opening NewStock.txt FOR WRITE is right because it is a new file, but Stock.txt must be FOR READ: opening the input file for writing would empty it. The EOF test goes before the read, and both files must be closed.
CompareAO26 marks
Compare serial, sequential and random file organisation, and explain which would be most suitable for a system that must look up and update a single customer record at a time.

Mark scheme — tick each point you actually made

Examiner tip: Compare means all three in the answer, with the access method named for each. The final mark is the judgement: name random and say why the other two fail for a single-record lookup, rather than describing random alone.

Exam technique for this topic

  • For a question on the characteristics of a paradigm, write the same five sentences each time: what the programmer writes, what the language provides, what it is good at, what it is poor at, and one situation where you would choose it. Marks are for the distinctive features, not for a definition of the word.
  • For addressing modes, state what the operand is every time: the value (immediate), the address of the value (direct), the address of the address (indirect), an address plus the index register (indexed), or a displacement from the current address (relative). A trace showing ACC, IX and the contents of the address before and after is the safest way to earn every mark.
  • In an OOP answer, use the terminology inside a sentence about the class you have designed: 'Balance is private, so it can only be changed through Deposit, which is encapsulation'. A list of definitions with no reference to the scenario rarely gets past half marks, and inheritance has to be justified by an is-a relationship.
  • In a declarative answer, label the parts explicitly: the head is the conclusion, the body is the conditions, and the variables are the links between them. A statement with no body is a fact, and a set of facts with no rules cannot answer a question that needs reasoning.
  • In a file question, use the exact command names in capitals - OPENFILE, READFILE, WRITEFILE, CLOSEFILE, SEEK, GETRECORD, PUTRECORD, EOF - and check the order: open in the right mode, loop while not EOF, read one record, process it, close. Put the operations inside a TRY block whenever the question mentions a file that might not exist.

Why students lose marks here

A student wroteA student wrote: 'A programming paradigm is a type of programming language, so Java is an object-oriented paradigm and Python is an imperative paradigm.'
Why it loses marksThis confuses a style of programming with a language. A paradigm is a way of approaching and structuring a solution, and most modern languages support several of them, so the same language can be used in more than one paradigm.
The answer that scoresA programming paradigm is a style or approach to writing programs, defined by the features a language provides and by the way the problem is broken down. Low-level, imperative (procedural), object-oriented and declarative programming are the four in this syllabus. A language is not a paradigm: Python can be written as a procedural program or as an object-oriented one, and Java can be written in a largely procedural style even though it is designed for objects. Low-level, imperative and object-oriented programming are all imperative, because the programmer writes the steps; declarative programming is not, because the programmer writes facts and rules and the system decides the order.
A student wroteA student wrote: 'Immediate addressing means the operand is the address of the data, so LDM #25 loads the contents of memory location 25 into the accumulator.'
Why it loses marksThe two modes have been swapped. Immediate addressing puts the value itself in the operand, which is what the # signals; loading the contents of an address is direct addressing. The answer also ignores the #, which exists precisely to mark the operand as a value.
The answer that scoresImmediate addressing puts the value itself in the operand, so LDM #25 places the number 25 in the accumulator and no memory access is needed to fetch it; the value is fixed when the program is written. Direct addressing puts the address of the value in the operand, so LDD 25 would load the contents of memory location 25. Indirect addressing puts the address of an address in the operand, so LDI 25 would look in location 25, find an address stored there and load the contents of that second address. Indexed addressing adds the index register to the operand address, and relative addressing treats the operand as a displacement from the current instruction.
A student wroteA student wrote: 'A sequential file is a file that has to be read in order, and a serial file is one that has been sorted into order by its key field.'
Why it loses marksThe two definitions have been swapped. It is the sequential file that is ordered by a key field; a serial file is in the order the records happened to be added, with no key order at all. Both are read sequentially, which is why the definitions are easy to mix up.
The answer that scoresA serial file holds records in the order they were written and has no ordering by any key, so it is read from the beginning when every record is being processed; a log of transactions or a backup is serial. A sequential file holds records in order of a key field such as an account number, is read in that order, and is updated in a batch by merging the master file with a transaction file to produce a new master file. A random file holds fixed-length records at positions that can be calculated from the key, so SEEK moves the pointer straight to a record and it can be read or replaced without reading the records before it, which is what makes it suitable for looking up and updating one record at a time.
A student wroteA student wrote: 'Exception handling means checking that the data the user enters is valid, so every input statement should be put inside a TRY block.'
Why it loses marksThis confuses exception handling with validation. Validation tests input that is predictably capable of being wrong, using IF statements, and it belongs in the logic of the program. Exception handling deals with run-time errors that the program cannot rule out in advance, and catching everything hides genuine bugs instead of fixing them.
The answer that scoresValidation checks input against the rules of the problem - a mark between 0 and 100, an age that is a positive whole number - and it is written with IF statements as part of the normal logic. Exception handling deals with an error or unexpected event raised while the program runs, such as a file that does not exist, a value that cannot be converted to a number, or a division by zero. It is appropriate where the failure is outside the program's control, and the TRY block should contain only the operations that can fail, with the EXCEPT block doing something useful: reporting the problem, using a default, asking for another file name or closing files cleanly.
A student wroteA student wrote: 'Inheritance means that one class contains another class as an attribute, so a Car inherits an Engine.'
Why it loses marksThat is containment, also called aggregation, which models a has-a relationship. Inheritance models an is-a relationship, in which a subclass takes on the attributes and methods of a superclass and can add to or override them. The relationship named and the relationship described do not match.
The answer that scoresInheritance is an is-a relationship: a SavingsAccount is a BankAccount, so the subclass inherits the attributes and methods of the superclass, adds an interest rate, and overrides CalculateInterest with its own version. Containment or aggregation is a has-a relationship: a Car has an Engine, so the Engine is an attribute of the Car and the Car's methods call the Engine's methods. A Car cannot inherit from an Engine, because a car is not an engine; inheriting there would give the Car the Engine's attributes directly and break as soon as the Engine class changed.