✓ Free · Component 2 · 2.2.1 Problem Solving & Programming
2.2.1a Programming Techniques
OCR H446 · A Level Computer Science · ~20 min read
Notes
Video
Slides
Worksheet
Quiz

Programming Paradigms

A programming paradigm is a style or approach to programming. Different paradigms suit different problems. OCR H446 requires knowledge of four key paradigms:

ParadigmCore ideaExamples
Procedural / ImperativeStep-by-step instructions; sequence, selection, iterationPython (basic), C, Pascal
Object-Oriented (OOP)Objects with data and behaviour; encapsulation, inheritance, polymorphismPython (OOP), Java, C++
FunctionalFunctions as first-class objects; avoid state and mutable data; higher-order functionsHaskell, Erlang; Python supports some features
DeclarativeDescribe WHAT is wanted, not HOW; the runtime/engine works it outSQL, HTML, Prolog

Object-Oriented Programming (OOP)

OOP organises code around objects — instances of classes that bundle together data (attributes) and behaviour (methods). The four pillars of OOP are:

Encapsulation

Bundling data (attributes) and the methods that operate on it into a single class, and hiding internal implementation by making attributes private. Only the public interface (methods) is exposed. This prevents accidental modification of internal state.

Inheritance

A child class (subclass) inherits attributes and methods from a parent class (superclass). The child can override methods or add new ones. Promotes code reuse and represents an IS-A relationship (a Dog IS-A Animal).

Polymorphism

Different classes respond to the same method name in different ways. Example: Animal.makeSound() could produce "Woof" for a Dog and "Meow" for a Cat. The calling code doesn't need to know the specific type — it just calls makeSound().

Abstraction (in OOP)

Hiding implementation detail behind a public interface. Users of a class interact through its methods without needing to understand the internal code. Related to, but distinct from, abstraction as a computational thinking technique.

Classes and Objects

A class is a blueprint/template. An object is an instance of a class. A class defines attributes (data) and methods (behaviour). The __init__ constructor sets up initial attribute values when an object is created.

class Animal:
    def __init__(self, name, sound):
        self.__name = name      # private attribute
        self.__sound = sound

    def speak(self):            # public method
        return self.__name + " says " + self.__sound

dog = Animal("Dog", "Woof")
print(dog.speak())  # Dog says Woof

Inheritance Example

class Shape:
    def __init__(self, colour):
        self.colour = colour
    def area(self):
        return 0

class Circle(Shape):
    def __init__(self, colour, radius):
        super().__init__(colour)
        self.radius = radius
    def area(self):             # override parent method
        return 3.14159 * self.radius ** 2

Functional Programming

Functional programming treats computation as the evaluation of mathematical functions. Key features:

  • First-class functions: Functions can be passed as arguments, returned from other functions, and stored in variables.
  • Higher-order functions: Functions that take other functions as arguments or return functions. Examples: map(), filter(), reduce().
  • Pure functions: Given the same inputs, always produce the same output; no side effects (don't modify external state).
  • Immutability: Data is not modified — new data structures are created instead.
  • Statelessness: No shared mutable state; avoids the problems of concurrency (race conditions, deadlocks).
# Higher-order functions in Python
nums = [1, 2, 3, 4, 5, 6]

evens = list(filter(lambda x: x % 2 == 0, nums))   # [2, 4, 6]
doubled = list(map(lambda x: x * 2, nums))           # [2, 4, 6, 8, 10, 12]

# Function passed as argument
def apply(func, value):
    return func(value)

print(apply(lambda x: x**2, 5))  # 25

Recursion

Recursion is when a function calls itself. It is a key technique in both functional and procedural programming. Every recursive function needs:

  • Base case: The condition under which the function stops calling itself (prevents infinite recursion)
  • Recursive case: The function calls itself with a smaller/simpler version of the problem
def factorial(n):
    if n == 0:          # base case
        return 1
    return n * factorial(n - 1)  # recursive case

# factorial(5) → 5 * factorial(4) → 5 * 4 * factorial(3) → ...
# → 5 * 4 * 3 * 2 * 1 = 120

Each recursive call adds a new stack frame. Deep recursion can cause a stack overflow if the call stack runs out of memory. Tail recursion (where the recursive call is the last operation) can be optimised by some languages to avoid this.

Procedural Programming

The most fundamental paradigm. Code is a sequence of instructions. The key constructs are: sequence, selection (if/else), iteration (while/for), and sub-routines (functions/procedures). Variables, parameters, return values, and local/global scope are all part of procedural thinking.

Global and Local Variables

Local variableGlobal variable
ScopeInside the function/block where declaredEntire program
LifetimeCreated when function called, destroyed when it returnsExists for entire program run
AccessOnly by the owning functionAny function (can read; writing needs global keyword in Python)
Side effectsNone — cannot affect other functionsRisk of unintended modification from any function
RecommendationPreferred — safer, more maintainableAvoid where possible — use parameters/return values instead
Exam tip: Know all four OOP pillars with examples. Polymorphism is often the weakest area — be sure you can explain it and give an example. Recursion questions frequently appear — always identify the base case and recursive case explicitly.
Exam tip: For functional programming: first-class functions, higher-order functions, pure functions, immutability, and statelessness are all key terms. map(), filter(), and reduce() are the canonical examples.
✓ Notes completed!
Video coming soon
Click to advance · Arrow keys also work
Click slide or press arrow keys to navigate

Worksheet — 2.2.1a Programming Techniques

8 questions · 24 marks · instantly marked

Q1Name the four main programming paradigms and give one language example for each.[4 marks]
✓ Mark scheme
Procedural/Imperative — Python basic, C, Pascal [1]. Object-oriented (OOP) — Java, C++, Python OOP [1]. Functional — Haskell, Erlang (Python has functional features) [1]. Declarative — SQL, Prolog, HTML [1]. (Any reasonable language example for each paradigm accepted)
Q2Explain the four pillars of object-oriented programming.[4 marks]
✓ Mark scheme
Encapsulation: bundling data (attributes) and methods into a class; hiding internal state behind a public interface [1]. Inheritance: a subclass inherits attributes and methods from a superclass; child can override or add methods; promotes code reuse [1]. Polymorphism: different classes respond to the same method name in different ways; calling code doesn't need to know the specific type [1]. Abstraction: hiding implementation detail behind a public interface; users interact with objects via methods without knowing the internal code [1].
Q3Write a Python class called BankAccount with a private balance attribute, a constructor that sets the initial balance, and two methods: deposit(amount) and get_balance().[4 marks]
✓ Mark scheme
class BankAccount: [1]
    def __init__(self, initial_balance): [0.5 — constructor with parameter]
        self.__balance = initial_balance [0.5 — private attribute with __]
    def deposit(self, amount): [1 — method updates balance]
        self.__balance += amount
    def get_balance(self): [1 — returns private attribute]
        return self.__balance
(Private attribute uses name mangling __ prefix; constructor sets initial value; deposit modifies balance; get_balance accesses it)
Q4Explain what recursion is and why a base case is essential.[3 marks]
✓ Mark scheme
Recursion is when a function calls itself [1]. A base case is a condition under which the function stops calling itself and returns a value directly [1]. Without a base case, the function would call itself indefinitely, adding stack frames until the call stack is exhausted — causing a stack overflow error [1].
Q5Write a recursive Python function to compute the nth Fibonacci number (fib(0)=0, fib(1)=1, fib(n)=fib(n-1)+fib(n-2)). Identify the base cases.[3 marks]
✓ Mark scheme
def fib(n): [1 — correct function signature]
    if n == 0: return 0    # base case 1 [1 — both base cases present]
    if n == 1: return 1    # base case 2
    return fib(n-1) + fib(n-2)  # recursive case [1]
Base cases: n==0 returns 0; n==1 returns 1. These stop the recursion. (Note: naive recursive Fibonacci is exponential time — for exam, correctness of recursion structure is assessed.)
Q6Explain three features of functional programming that distinguish it from procedural programming.[3 marks]
✓ Mark scheme
Any 3 of: First-class functions — functions can be passed as arguments, returned from functions, and stored in variables (in procedural, functions are called but not treated as data) [1]. Higher-order functions — functions that take/return other functions, e.g. map, filter, reduce [1]. Pure functions — same input always gives same output; no side effects; procedural functions often modify external state [1]. Immutability — data is not changed; new structures are created; procedural programs routinely modify variables [1]. Statelessness — no shared mutable state; avoids race conditions; procedural programs use global state freely [1].
Q7Using Python, demonstrate the use of map() to square each number in the list [1, 2, 3, 4, 5].[2 marks]
✓ Mark scheme
result = list(map(lambda x: x**2, [1, 2, 3, 4, 5])) [1 — correct use of map with lambda/function]
print(result) # [1, 4, 9, 16, 25] [1 — correct output or demonstrated]
Alternative: def square(x): return x**2; result = list(map(square, [1,2,3,4,5])) — also acceptable. list() required to materialise the map object in Python 3.
Q8Explain what is meant by polymorphism in OOP. Give a concrete example with two subclasses.[4 marks]
✓ Mark scheme
Polymorphism means different classes can respond to the same method name in different ways [1]. The calling code doesn't need to know the specific type of object — it calls the method and each class provides its own implementation [1]. Example: Shape subclasses Circle and Rectangle both have an area() method, but each calculates area differently (πr² vs l×w) [1]. Code that calls shape.area() works correctly for both without knowing which type it has — the correct implementation is selected at runtime [1]. (Other valid examples: Animal.speak() returning different sounds for Dog/Cat; Employee.calculate_pay() working differently for HourlyWorker/SalariedWorker)
Topic Quiz
1 of 15
You scored
out of 15
🎯

Mini Test — 2.2.1a Programming Techniques

  • 10 questions · 10 marks · 10 minutes
  • 5 MCQ + 5 short answer
Card 1 of 15
Click to reveal
🎉
Complete!
TermDefinition
← 2.1.1b Thinking Ahead & Concurrently 2.2.1 Problem Solving & Programming Next: 2.2.1b File & Exception Handling →