Learning Objectives
By the end of this lesson, you will be able to:
- Define what a programming paradigm is and explain its importance
- Identify and describe the four main programming paradigms: Imperative, Object-Oriented, Functional, and Declarative
- Write simple programs using each programming paradigm approach
- Explain the purpose and characteristics of low-level programming
- Understand and apply different addressing modes in assembly language
- Write basic assembly language programs using Cambridge 9618-style syntax
- Compare and contrast different programming paradigms and their applications
- Recognize real-world applications of different programming paradigms
Key Terms
Programming Paradigm
A way of thinking about and organizing code with specific rules and styles
Imperative Programming
Uses step-by-step instructions to change program state (also called Procedural)
Object-Oriented Programming (OOP)
Organizes code into objects that have properties and behaviors
Functional Programming
Focuses on functions and avoids changing state (uses pure functions)
Declarative Programming
Defines rules instead of writing step-by-step instructions
Low-Level Programming
Writing code that directly interacts with the CPU using assembly language
Addressing Mode
Determines how the CPU retrieves data from memory
Opcode
The operation to perform in assembly language (e.g., LDM, ADD)
Operand
The data or memory location to use in an assembly instruction
Register
A small storage unit inside the CPU (e.g., ACC, IX)
Sequence
Step-by-step execution of instructions in imperative programming
Selection
Making decisions in programs using conditions (if-else statements)
Iteration
Repeating code using loops (for, while) until a condition is met
Procedure
A block of code that performs a task but does not return a value
Function
Similar to a procedure but returns a value
20.1.1 Understanding Programming Paradigms
A programming paradigm is a way of thinking about and organizing code. It defines rules, techniques, and styles that programmers follow to write programs. Different paradigms help solve problems in different ways, and some programming languages support multiple paradigms.
Real-Life Example: Cooking Instructions
Think about different ways to give cooking instructions:
- Imperative: "Chop onions, heat oil, sauté onions for 5 minutes, add tomatoes..." (step-by-step recipe)
- Declarative: "Make me a pizza" (describe the goal, let the chef figure out the steps)
Similarly, programming paradigms define different ways of telling a computer what to do!
Why Different Paradigms?
Different Problem Types
Some problems are easier to solve with objects, others with functions
Code Organization
Different ways to structure and maintain large codebases
Performance & Efficiency
Some paradigms are better for certain types of computations
Types of Programming Paradigms
| Paradigm | Key Idea | Example Language |
|---|---|---|
| Imperative (Procedural) | Step-by-step instructions | C, Python, Java |
| Object-Oriented (OOP) | Organizes code into objects | Java, Python, C++ |
| Functional | Focuses on functions and immutability | Haskell, Lisp, Scala |
| Declarative (Logic-based) | Defines rules, not steps | Prolog, SQL |
Programming Paradigms Visualization
Imperative
Step-by-step instructions like a recipe
for i in range(1, 6):
total += i
print(total)
Object-Oriented
Organizes code into objects
def __init__(self, brand):
self.brand = brand
def display(self):
print(self.brand)
Functional
Uses pure functions, no side effects
return 1 if n == 0
else n * factorial(n-1)
Declarative
Defines rules, not steps
parent(alice, emma).
grandparent(X,Y) :-
parent(X,Z), parent(Z,Y).
Note: Some languages like Python support multiple paradigms. You can write imperative, object-oriented, or functional code in Python!
Imperative (Procedural) Programming
Uses step-by-step instructions to change program state. It's one of the most common programming styles and is used in languages like Python, C, and Java.
Imperative Code Execution Simulation
Watch how this Python program executes step-by-step:
How it works: Imperative programming follows a sequence of instructions. The computer executes them one after another, changing the program's state (variables) as it goes.
1. Sequence
The program runs instructions one after another
print("Hello, " + name)
2. Selection
Programs can choose different actions based on conditions
if age >= 18:
print("Can vote")
else:
print("Cannot vote")
3. Iteration
Loops repeat code until a condition is met
print("Iteration:", i)
Object-Oriented Programming (OOP)
Organizes code into objects that have properties and behaviors. Supports inheritance, polymorphism, and encapsulation for code reusability.
Real-Life OOP Example: School System
Objects in a School
- Student object with properties: name, age, student_id
- Teacher object with properties: name, subject, teacher_id
- Classroom object with properties: room_number, capacity
- Course object with properties: course_name, credits
OOP Concepts Applied
- Encapsulation: Student grades are private data
- Inheritance: Teacher and Student inherit from Person class
- Polymorphism: Different calculateGrade() methods
- Abstraction: You don't need to know how attendance is tracked internally
Functional Programming
Focuses on functions and avoids changing state. Uses pure functions (no side effects) and recursion instead of loops.
Key Features of Functional Programming
- Pure Functions: Same input always gives same output, no side effects
- Immutability: Data cannot be changed after creation
- First-Class Functions: Functions can be assigned to variables, passed as arguments
- Higher-Order Functions: Functions that take other functions as parameters
def add(a, b):
return a + b
# Higher-order function example
def apply_twice(func, x):
return func(func(x))
# Using the function
result = apply_twice(lambda x: x * 2, 5)
# result = 20 (5*2*2)
Declarative Programming
Defines rules instead of writing step-by-step instructions. Works without defining how to get results. Common in AI and databases.
SQL Example (Declarative)
In SQL, you declare what data you want, not how to get it:
FROM students
WHERE age > 18
ORDER BY name;
You don't tell the database how to search, sort, or retrieve the data. You just declare what you want!
Prolog Example (Logic-based)
Prolog uses facts and rules:
parent(john, alice).
parent(alice, emma).
% Rule
grandparent(X, Y) :-
parent(X, Z), parent(Z, Y).
% Query
?- grandparent(john, emma).
% Answer: true
Comparing Programming Paradigms
| Paradigm | Uses Loops? | Uses Objects? | Uses Functions? | Uses Rules? |
|---|---|---|---|---|
| Imperative | Yes | No | Yes | No |
| OOP | Yes | Yes | Yes | No |
| Functional | No | No | Yes | No |
| Declarative | No | No | No | Yes |
Activity 1: Write an Imperative Program
Task 1: Write a Python program that adds numbers from 1 to 10 using a loop.
Task 2: Modify it to print only even numbers from 1 to 20.
Hint
Use a for loop and an if statement for Task 2. Remember: a number is even if number % 2 == 0.
Solution:
Task 1 Solution:
for i in range(1, 11):
total += i
print("Sum from 1 to 10:", total)
Output: Sum from 1 to 10: 55
Task 2 Solution:
if i % 2 == 0:
print(i, "is even")
Output: 2 is even, 4 is even, 6 is even... 20 is even
Activity 2: Create an OOP Program
Task 1: Define a class for a Student with properties name and age.
Task 2: Create an object for a student and print the details.
Task 3: Add a method to the Student class that returns whether the student is an adult (age >= 18).
Hint
Use __init__ for initialization and create a method like is_adult() that returns True or False.
Solution:
def __init__(self, name, age):
self.name = name
self.age = age
def display_info(self):
print(f"Student: {self.name}, Age: {self.age}")
def is_adult(self):
return self.age >= 18
# Create student object
student1 = Student("Alice", 20)
student1.display_info()
# Check if adult
if student1.is_adult():
print(f"{student1.name} is an adult")
else:
print(f"{student1.name} is not an adult")
Output:
Student: Alice, Age: 20
Alice is an adult
Check Your Understanding: Programming Paradigms
1. What is a programming paradigm? [2 marks]
Answer
- [1 mark] A programming paradigm is a way of thinking about and organizing code
- [1 mark] It defines rules, techniques, and styles that programmers follow to write programs
- [Additional] Different paradigms help solve problems in different ways, and some languages support multiple paradigms
2. Name the four main programming paradigms and give one example language for each. [4 marks]
Answer
- [1 mark] Imperative (Procedural) - Example: C, Python, Java
- [1 mark] Object-Oriented (OOP) - Example: Java, Python, C++
- [1 mark] Functional - Example: Haskell, Lisp, Scala
- [1 mark] Declarative (Logic-based) - Example: Prolog, SQL
3. What are the three main ideas in imperative programming? [3 marks]
Answer
- [1 mark] Sequence - Step-by-step execution of instructions
- [1 mark] Selection - Making decisions using conditions (if-else statements)
- [1 mark] Iteration - Repeating code using loops (for, while)
4. How does functional programming differ from imperative programming? [3 marks]
Answer
- [1 mark] Functional programming uses pure functions with no side effects, while imperative programming changes program state
- [1 mark] Functional programming avoids loops and variables, using recursion instead
- [1 mark] Functional programming focuses on immutability (data cannot be changed), while imperative programming frequently modifies data
5. Give a real-life example of declarative programming. [2 marks]
Answer
- [1 mark] SQL database queries - You declare what data you want, not how to get it
- [1 mark] HTML/CSS - You declare how a webpage should look, not the step-by-step drawing instructions
- [Additional] Prolog logic programming - You define facts and rules, not step-by-step algorithms
6. What are the key features of Object-Oriented Programming? [3 marks]
Answer
- [1 mark] Uses classes and objects to organize code
- [1 mark] Supports inheritance (creating new classes from existing ones)
- [1 mark] Includes polymorphism (objects can take many forms) and encapsulation (hiding internal details)
20.1.2 Low-Level Programming & Addressing Modes
Low-level programming is the foundation of computer operations. It involves writing assembly language code that directly controls the CPU. Understanding addressing modes is crucial as they determine how the CPU accesses data in memory.
Why Learn Low-Level Programming?
- More control over hardware - Directly manipulate CPU and memory
- Faster execution than high-level languages for certain tasks
- Essential for understanding how computers actually work
- Used in operating systems, embedded systems, and performance-critical applications
Key Assembly Language Concepts
Opcode
The operation to perform (e.g., LDM, ADD, STO)
Operand
The data or memory location to use (e.g., #10, MEMORY1)
Register
Small storage unit inside CPU (e.g., ACC, IX)
Addressing Modes
An addressing mode determines how the CPU retrieves data from memory. There are five main types used in Cambridge 9618 assembly language.
Addressing Modes Memory Visualization
How it works: Different addressing modes access memory in different ways. The visualization shows how each mode retrieves data from memory locations.
1. Immediate Addressing (LDM #N, LDR #N)
How It Works
- The operand is a direct value
- The value is stored immediately in the register
- Uses # symbol before the value
Example Code
LDM #10
; Load immediate value 5 into index register
LDR #5
2. Direct Addressing (LDD)
How It Works
- The operand is a memory location
- The value stored at that address is loaded into the accumulator
- Goes directly to the memory address specified
Example Code
LDD MEMORY1
; If MEMORY2 stores 15, this loads 15 into ACC
LDD MEMORY2
3. Indirect Addressing (LDI)
How It Works
- The address provided stores another address
- The CPU retrieves the final address first, then loads the value stored there
- Two-step process: get address, then get value
Example Code
LDI POINTER1
; If POINTER1 contains address 0x100, and
; address 0x100 contains value 42, then 42 is loaded
4. Indexed Addressing (LDX)
How It Works
- Final address = Base Address + Value in Index Register (IX)
- Useful for arrays and looping through memory
- Allows accessing elements at calculated positions
Example Code
LDR #2
; Load value from ARRAY + 2 into accumulator
LDX ARRAY
; If ARRAY starts at address 0x200, this loads
; value from address 0x202 (0x200 + 2)
5. Relative Addressing (JMP, JPE, JPN)
How It Works
- Used for jumping to a new instruction based on current position
- Often used in loops and conditional statements
- Jumps relative to current program counter
Example Code
CMP #10
; If equal, jump to label LOOP
JPE LOOP
; Unconditional jump to END label
JMP END
Complete Example Program
; Cambridge 9618-style assembly language
LDM #5 ; Immediate: Load 5 into ACC
STO MEMORY1 ; Store ACC into MEMORY1
LDD MEMORY1 ; Direct: Load from MEMORY1 into ACC
LDI POINTER1 ; Indirect: Load from address in POINTER1
LDR #2 ; Load 2 into Index Register (IX)
LDX ARRAY ; Indexed: Load from ARRAY + IX into ACC
CMP #10 ; Compare ACC with 10
JPE END ; If equal, jump to END
LOOP: ADD #1 ; Add 1 to ACC
JMP LOOP ; Jump back to LOOP (infinite loop)
END: END ; Terminate program
Activity 3: Assembly Language Practice
Task 1: Write an assembly instruction to load the number 25 into the accumulator using immediate addressing.
Task 2: If MEMORY2 stores the number 15, write an instruction to load this value into the accumulator using direct addressing.
Task 3: Write an instruction that retrieves an address from POINTER2 and loads its value into the accumulator using indirect addressing.
Task 4: Write instructions that load the value from LIST + 3 into the accumulator using indexed addressing.
Hint
For Task 4: First load 3 into IX using LDR #3, then use LDX LIST.
Solution:
Task 1 Solution:
Loads the immediate value 25 into the accumulator.
Task 2 Solution:
Loads the value stored at memory location MEMORY2 (which is 15) into ACC.
Task 3 Solution:
Gets an address from POINTER2, then loads the value from that address into ACC.
Task 4 Solution:
LDX LIST
Loads 3 into IX, then loads value from memory address LIST + 3 into ACC.
Activity 4: Complete Assembly Program
Modify the example program to:
- Load #8 into ACC (instead of #5)
- Store it in MEMORY2 (instead of MEMORY1)
- Use indexed addressing to access LIST + 4 (instead of ARRAY + 2)
- Compare ACC with 12 (instead of 10)
Hint
Remember to use LDR #4 for the index register before LDX LIST. Also change the comparison value to #12.
Solution:
LDM #8 ; Immediate: Load 8 into ACC
STO MEMORY2 ; Store ACC into MEMORY2
LDD MEMORY2 ; Direct: Load from MEMORY2 into ACC
LDI POINTER1 ; Indirect: Load from address in POINTER1
LDR #4 ; Load 4 into Index Register (IX)
LDX LIST ; Indexed: Load from LIST + 4 into ACC
CMP #12 ; Compare ACC with 12
JPE END ; If equal, jump to END
LOOP: ADD #1 ; Add 1 to ACC
JMP LOOP ; Jump back to LOOP
END: END ; Terminate program
Key changes: Changed immediate value from #5 to #8, storage location from MEMORY1 to MEMORY2, index value from #2 to #4, base address from ARRAY to LIST, and comparison value from #10 to #12.
Check Your Understanding: Low-Level Programming
1. What is low-level programming and why is it important? [3 marks]
Answer
- [1 mark] Low-level programming involves writing assembly language code that directly controls the CPU
- [1 mark] It provides more control over hardware and faster execution than high-level languages
- [1 mark] It's essential for understanding how computers work and is used in operating systems, embedded systems, and performance-critical applications
2. What is an addressing mode? Name the five main types. [6 marks]
Answer
- [1 mark] An addressing mode determines how the CPU retrieves data from memory
- [1 mark] Immediate Addressing (LDM #N, LDR #N)
- [1 mark] Direct Addressing (LDD)
- [1 mark] Indirect Addressing (LDI)
- [1 mark] Indexed Addressing (LDX)
- [1 mark] Relative Addressing (JMP, JPE, JPN)
3. Explain the difference between direct and indirect addressing. [4 marks]
Answer
Direct Addressing:
- Operand is a memory location
- Value stored at that address is loaded directly
- One-step process: go to address, get value
- Example: LDD MEMORY1
Indirect Addressing:
- Address provided stores another address
- CPU retrieves final address first, then gets value
- Two-step process: get address, then get value
- Example: LDI POINTER1
4. How does indexed addressing work and when is it useful? [3 marks]
Answer
- [1 mark] Final address = Base Address + Value in Index Register (IX)
- [1 mark] Useful for arrays and looping through memory elements
- [1 mark] Allows accessing elements at calculated positions without hardcoding each address
- [Additional] Example: First load index with LDR #3, then use LDX ARRAY to access ARRAY + 3
5. What is the purpose of relative addressing? [2 marks]
Answer
- [1 mark] Used for jumping to a new instruction based on current position
- [1 mark] Often used in loops and conditional statements to control program flow
- [Additional] Examples: JMP (unconditional jump), JPE (jump if equal), JPN (jump if negative)
6. Write assembly code to: a) Load 42 into ACC, b) Store it in DATA1, c) Load it back using direct addressing. [3 marks]
Answer
LDM #42
; Store ACC value into memory location DATA1
STO DATA1
; Load value from DATA1 back into ACC using direct addressing
LDD DATA1
This code loads 42 into ACC, stores it at memory location DATA1, then loads it back from DATA1 into ACC.
20.1.3 Imperative (Procedural) Programming
Imperative (procedural) programming is a method where programs follow a list of instructions in order to complete a task. These instructions change variables, control program flow, and perform calculations.
Real-Life Analogy: Following a Recipe
Think of imperative programming like following a recipe:
- Get ingredients (initialize variables)
- Mix ingredients (perform operations)
- Cook the food (process data)
- Serve the dish (output results)
Each step must be followed in the correct sequence for the dish to turn out right. Similarly, a computer follows instructions in an imperative program to get the correct result.
Procedures and Functions
Procedures (Subroutines)
A procedure is a block of code that performs a task but does not return a value.
print("Hello, welcome!")
# Calling the procedure
greet()
Procedures help organize code into reusable blocks, making programs easier to read and maintain.
Functions (with Return Values)
A function is like a procedure but returns a value.
return num * num
# Using the function
result = square(4)
print(result) # Output: 16
Functions are useful for calculations that produce a result you need to use elsewhere in your program.
Complete Example Program
def is_even(num):
if num % 2 == 0:
return True
else:
return False
# Main program
for i in range(1, 6):
if is_even(i):
print(i, "is even")
else:
print(i, "is odd")
Program breakdown:
- Function definition: is_even() checks if a number is even
- Sequence: Code executes line by line from top to bottom
- Iteration: for loop repeats for numbers 1 through 5
- Selection: if-else statement chooses what to print
- Function call: is_even(i) is called inside the loop
Final Task: Identify Programming Paradigms
Look at the following code snippets. Identify which programming paradigm they belong to:
Snippet 1:
print(i)
Snippet 2:
def bark(self):
print("Woof!")
Snippet 3:
return x * x
Snippet 4:
Hint
Think about whether they use loops (imperative), objects (OOP), functions (functional), or rules (declarative).
Solution:
Snippet 1: Imperative (Procedural) Programming
Uses a for loop (iteration), which is characteristic of imperative programming.
Snippet 2: Object-Oriented Programming (OOP)
Defines a class with a method, which is characteristic of OOP.
Snippet 3: Functional Programming
Defines a pure function that returns a value based only on its input, characteristic of functional programming.
Snippet 4: Declarative Programming
Defines a fact/rule (in Prolog syntax), which is characteristic of declarative/logic programming.
Note: Some languages like Python support multiple paradigms, so code snippets could potentially fit more than one paradigm depending on context.
Key Takeaways
- Programming paradigms are different ways of thinking about and organizing code
- Imperative programming uses step-by-step instructions with sequence, selection, and iteration
- Object-Oriented Programming (OOP) organizes code into objects with properties and behaviors
- Functional programming focuses on pure functions and avoids changing state
- Declarative programming defines rules instead of step-by-step instructions
- Low-level programming involves writing assembly language that directly controls the CPU
- Addressing modes determine how the CPU retrieves data from memory (immediate, direct, indirect, indexed, relative)
- Immediate addressing loads a direct value into a register (LDM #N)
- Direct addressing loads a value from a specific memory location (LDD)
- Indirect addressing uses an address that stores another address (LDI)
- Indexed addressing calculates addresses as base + index register (LDX)
- Relative addressing is used for jumps and loops (JMP, JPE, JPN)
- Some languages like Python support multiple programming paradigms
- Understanding different paradigms helps choose the right approach for different programming problems
Question Bank
1. Explain what a programming paradigm is and why different paradigms exist. [4 marks]
Marking Scheme & Answer
- [1 mark] A programming paradigm is a way of thinking about and organizing code with specific rules and styles
- [1 mark] Different paradigms exist because some problems are easier to solve with certain approaches
- [1 mark] Different paradigms provide different ways to structure and maintain large codebases
- [1 mark] Some paradigms are more efficient or suitable for specific types of computations
- [Additional] Examples: OOP for modeling real-world systems, functional for mathematical computations, imperative for straightforward algorithms
2. Compare and contrast imperative and declarative programming. [5 marks]
Marking Scheme & Answer
Imperative Programming:
- Uses step-by-step instructions
- Focuses on HOW to achieve the result
- Changes program state
- Uses variables, loops, conditions
- Example: Python, C, Java
Declarative Programming:
- Defines rules and constraints
- Focuses on WHAT result is wanted
- Doesn't specify step-by-step process
- Uses facts, rules, queries
- Example: SQL, Prolog, HTML
3. What are the three main concepts in imperative programming? Explain each with an example. [6 marks]
Marking Scheme & Answer
1. Sequence:
Instructions executed one after another in order.
print("Hello, " + name)
2. Selection:
Making decisions using conditions.
if age >= 18:
print("Can vote")
else:
print("Cannot vote")
3. Iteration:
Repeating code using loops.
print("Loop", i)
4. Explain the difference between immediate and direct addressing modes in assembly language. [4 marks]
Marking Scheme & Answer
Immediate Addressing:
- Operand is a direct value
- Value loaded immediately into register
- Uses # symbol before value
- Example: LDM #10
- Loads the number 10 into ACC
Direct Addressing:
- Operand is a memory location
- Value stored at that address is loaded
- Goes directly to memory address
- Example: LDD MEMORY1
- If MEMORY1 stores 15, loads 15 into ACC
5. Write an assembly language program that uses at least three different addressing modes. [6 marks]
Marking Scheme & Answer
LDM #5 ; 1. IMMEDIATE: Load 5 into ACC
STO VALUE ; Store ACC into VALUE memory location
LDD VALUE ; 2. DIRECT: Load from VALUE into ACC
LDR #2 ; Load 2 into index register IX
LDX ARRAY ; 3. INDEXED: Load from ARRAY+2 into ACC
CMP #10 ; Compare ACC with 10
JPE END ; 4. RELATIVE: Jump if equal to END
END: END ; Terminate program
6. What are the advantages and disadvantages of low-level programming compared to high-level programming? [6 marks]
Marking Scheme & Answer
Advantages of Low-Level Programming:
- More control: Direct manipulation of hardware resources
- Faster execution: No abstraction layers, closer to machine code
- Smaller code size: More efficient use of memory
- Essential knowledge: Understanding how computers actually work
Disadvantages of Low-Level Programming:
- Harder to write: More complex and error-prone
- Less portable: Code is specific to particular hardware
- Longer development time: More lines of code for same functionality
- Harder to maintain: Code is less readable and understandable
7. Describe how indexed addressing is used to access arrays in memory. [4 marks]
Marking Scheme & Answer
- [1 mark] Indexed addressing calculates memory address as: Address = Base Address + Index Register Value
- [1 mark] The base address points to the start of the array in memory
- [1 mark] The index register (IX) holds the position within the array (0 for first element, 1 for second, etc.)
- [1 mark] This allows accessing array elements without hardcoding each memory address
- [Additional] Example: If ARRAY starts at address 0x100, and IX contains 3, LDX ARRAY accesses element at address 0x103
LDR #2 ; Load 2 into IX (index register)
LDX ARRAY ; Load value from ARRAY[2] into ACC
8. Explain the concept of functional programming and give an example of a pure function. [4 marks]
Marking Scheme & Answer
- [1 mark] Functional programming focuses on using functions as the primary building blocks of programs
- [1 mark] It emphasizes pure functions that have no side effects (don't change external state)
- [1 mark] Pure functions always return the same output for the same input
- [1 mark] Functional programming avoids changing variables and uses recursion instead of loops
def add(a, b):
return a + b
# This function is pure because:
# 1. Same input (2, 3) always gives same output (5)
# 2. No side effects (doesn't change any external variables)
# 3. Return value depends only on input parameters
9. What is indirect addressing and why is it useful? [3 marks]
Marking Scheme & Answer
- [1 mark] Indirect addressing uses an address that contains another address pointing to the actual data
- [1 mark] It's useful for implementing data structures like linked lists and pointer-based structures
- [1 mark] Allows dynamic memory access where the target address can change during program execution
- [Additional] Example: LDI POINTER loads the value from the address stored in POINTER
10. How do procedures and functions help in imperative programming? [3 marks]
Marking Scheme & Answer
- [1 mark] Procedures and functions break programs into smaller, manageable pieces (modularization)
- [1 mark] They allow code reuse - write once, use many times
- [1 mark] They make programs easier to read, debug, and maintain
- [Additional] Functions also return values that can be used in expressions, while procedures perform actions without returning values