Programming Paradigms
1. Structured Programming
Key Idea: Replace unrestricted goto
with sequence, selection (if
/else
), and iteration (while
/for
). This makes code provably correct.
Example: Factorial Calculation ©
#include <stdio.h>
// Structured approach: No goto; uses loops and conditionals
int factorial(int n) {
int result = 1;
for (int i = 1; i <= n; i++) {
result *= i;
}
return result;
}
int main() {
printf("Factorial of 5: %d\n", factorial(5)); // 120
return 0;
}
Test Output:
Factorial of 5: 120
Why It Works:
- Uses
for
loops instead ofgoto
. - Easy to reason about correctness through structured flow.
2. Object-Oriented Programming (OOP)
Key Idea: Polymorphism enables dependency inversion. High-level policies depend on abstractions, not concrete details.
Example: Shape Hierarchy (Java)
// Abstraction: High-level policy depends on Shape interface
interface Shape {
double area();
}
// Concrete implementation
class Circle implements Shape {
private double radius;
public Circle(double radius) { this.radius = radius; }
@Override
public double area() { return Math.PI * radius * radius; }
}
// Another concrete implementation
class Rectangle implements Shape {
private double width, height;
public Rectangle(double w, double h) { width = w; height = h; }
@Override
public double area() { return width * height; }
}
public class Main {
public static void main(String[] args) {
Shape circle = new Circle(3);
Shape rect = new Rectangle(4, 5);
System.out.println("Circle area: " + circle.area()); // ~28.27
System.out.println("Rectangle area: " + rect.area()); // 20.0
}
}
Test Output:
Circle area: 28.274333882308138
Rectangle area: 20.0
Why It Works:
Shape
interface abstracts details (Dependency Inversion Principle).- New shapes (e.g.,
Triangle
) can be added without changing high-level code.
3. Functional Programming
Key Idea: Immutability and pure functions avoid side effects, making concurrency safer.
Example: Immutable Data (Python)
# Pure function: No side effects; returns new data
def square_numbers(nums):
return [x ** 2 for x in nums]
# Main test
original = [1, 2, 3, 4]
squared = square_numbers(original)
print("Original:", original) # Unmodified
print("Squared:", squared) # [1, 4, 9, 16]
Test Output:
Original: [1, 2, 3, 4]
Squared: [1, 4, 9, 16]
Why It Works:
square_numbers
doesn’t modify input (immutability).- Safe for concurrent execution (no shared mutable state).
Key Takeaways
Structured Programming:
- Uses control structures (
if
,for
,while
) instead ofgoto
. - Makes code verifiable through stepwise decomposition.
- Uses control structures (
OOP:
- Polymorphism inverts dependencies (high-level ↔ abstractions).
- Enables plug-in architecture (e.g., new
Shape
implementations).
Functional Programming:
- Avoids mutable state and side effects.
- Simplifies concurrency and testing.
Testing Strategy
- Structured: Verify outputs for known inputs (e.g., factorial of 5 = 120).
- OOP: Ensure abstractions work with multiple implementations.
- Functional: Check that data isn’t mutated and outputs are pure transformations.
Questions:
Which statements about programming paradigms are TRUE?
a) Paradigms remove capabilities from programmers
b) Object-oriented programming adds new capabilities to structured programming
c) All paradigms were discovered between 1958-1968
d) Functional programming primarily deals with indirect control transferWhat do the three programming paradigms have in common?
a) They all enable mathematical proofs of correctness
b) They impose restrictions on specific coding practices
c) They were all enabled by advances in hardware capabilities
d) They represent different approaches to concurrency managementWhich statements about structured programming are CORRECT?
a) It allows decomposition into provable units
b) Dijkstra advocated for unrestricted goto statements
c) It enables functional decomposition
d) It was primarily about improving performanceKey aspects of object-oriented programming include:
a) Safe polymorphism through function pointers
b) Automatic dependency inversion
c) Complete encapsulation implementation
d) Plugin architecture enablementFunctional programming’s main constraints:
a) Prohibition of sequence structures
b) Restrictions on variable mutation
c) Mandatory use of recursion
d) Immutable data structuresWhich paradigm relationships are CORRECT?
a) OOP builds on structured programming
b) Functional programming replaces OOP
c) Structured programming enables testable units
d) All paradigms can coexist in a systemAbout paradigm history:
a) Lisp was the first functional language
b) ALGOL inspired OOP discoveries
c) Church’s λ-calculus predates computers
d) Structured programming came last chronologicallyArchitectural implications include:
a) Structured programming for algorithm foundations
b) OOP for dependency management
c) Functional for data management
d) All paradigms are mutually exclusiveKey paradigm restrictions:
a) Structured: goto statements
b) OOP: direct function calls
c) Functional: variable assignment
d) All: specific code organizationAbout the “no new paradigms” claim:
a) Proved by advances in language theory
b) Based on fundamental computational limits
c) Supported by historical pattern
d) Refuted by recent concurrency paradigms
Answers & Explanations:
a, c
a) Correct. Paradigms restrict rather than add capabilities
c) Correct. All three main paradigms discovered in that decade
b) False. OOP doesn’t add new capabilities
d) False. OOP handles indirect controlb, d
b) Correct. Each restricts specific practices
d) Correct. All relate to concurrency indirectly
a) False. Only structured enables proofs
c) False. Not hardware-dependenta, c
a) Correct. Enables decomposition
c) Correct. Supports functional decomposition
b) False. Dijkstra opposed goto
d) False. About structure not performancea, d
a) Correct. Safe polymorphism via vtables
d) Correct. Enables plugin architecture
b) False. Manual dependency inversion needed
c) False. Encapsulation often incompleteb, d
b) Correct. Restricts variable mutation
d) Correct. Immutable data is key
a) False. Sequence allowed
c) False. Recursion not mandatorya, c, d
a) Correct. OOP builds on structured
c) Correct. Structured enables testable units
d) Correct. Can coexist
b) False. Paradigms complementa, c
a) Correct. Lisp (1958) first functional
c) Correct. λ-calculus predates computers
b) False. ALGOL influenced but not direct
d) False. Structured programming came latera, b, c
All correct per architectural implications in text
d) False. Can be combineda, c
a) Correct. Structured restricts goto
c) Correct. Functional restricts assignment
b) False. OOP uses indirect calls
d) False. About control flow not organizationb, c
b) Correct. Based on computation fundamentals
c) Correct. Historical pattern supports
a) False. Not formally proved
d) False. No fundamentally new paradigms
Test Code Examples:
- Structured Programming Test
#include <stdio.h>
void structured_example() {
int i = 0;
while(i < 5) { // Proper structured loop
printf("%d\n", i);
i++;
}
}
int main() {
structured_example();
return 0;
}
- OOP Polymorphism Test
interface Shape { double area(); }
class Circle implements Shape {
private double radius;
Circle(double r) { radius = r; }
public double area() { return Math.PI * radius * radius; }
}
class Square implements Shape {
private double side;
Square(double s) { side = s; }
public double area() { return side * side; }
}
public class Main {
public static void main(String[] args) {
Shape[] shapes = { new Circle(2), new Square(3) };
for (Shape s : shapes) {
System.out.println("Area: " + s.area());
}
}
}
- Functional Immutability Test
object FunctionalTest {
def main(args: Array[String]): Unit = {
val numbers = List(1, 2, 3)
val squared = numbers.map(x => x * x) // Immutable transformation
println(s"Original: $numbers")
println(s"Squared: $squared")
}
}
These examples demonstrate:
- Structured programming with controlled loops
- OOP polymorphism through interface implementation
- Functional programming with immutable data transformations