Foundations of Programming Paradigms

A paradigm provides a mental model for expressing computation.

1.1 What is a programming paradigm?

A paradigm provides a mental model for expressing computation.

Consider the task: find the sum of numbers from 1 through 5.

Imperative style — Python Output (CPython 3.13.1, one real run):

This describes steps: initialize a variable, iterate, update state, and print.

Functional style — Python Output (CPython 3.13.1): This emphasizes a value transformation and delegates iteration to a reusable function. The implementation of sum may still use imperative steps internally.

Declarative style — SQL Output (SQLite via Python 3.13.1, with a table number_values holding 1–5):

This states the desired result rather than explicitly describing the iteration. SQL's query engine decides how to execute the request.

These are different ways to express related intent. They are not mutually exclusive categories, and one style is not universally best.

total = 0

for number in range(1, 6):
    total += number

print(total)  # 15
numbers = [1, 2, 3, 4, 5]
total = sum(numbers)

print(total)  # 15
SELECT SUM(number_value) AS total
FROM number_values;

1.2 Major paradigm families

Imperative: describe commands and state changes.

Procedural: organize imperative commands into procedures or functions.

Structured: organize control flow using sequence, selection, and iteration rather than arbitrary jumps.

Object-oriented (OOP): organize behavior and state around objects and interfaces.

Functional: emphasize functions, expressions, composition, and controlled effects.

Declarative: specify desired results or relationships.

Logic: describe facts and rules, then ask queries.

Constraint-based: specify conditions a solution must satisfy.

Event-driven: execution responds to events.

Concurrent: multiple activities make progress with coordination.

Parallel: multiple computations execute simultaneously.

Reactive: values or streams propagate changes over time.

Dataflow: dependencies between values determine execution.

Data-oriented: organize data and processing to suit memory access and workload patterns.

Pipeline/stream processing: pass data through composable stages.

Aspect-oriented: isolate cross-cutting concerns such as logging or tracing.

Metaprogramming: programs generate, transform, or inspect programs.

Paradigm family map Text equivalent: paradigms are usually grouped into two broad families. Imperative approaches (procedural, structured, object-oriented, and most concurrent styles) describe *how* state changes step by step. Declarative approaches (functional, logic, constraint and query languages) describe *what* result or relationship is wanted. Event-driven, actor, reactive, dataflow and pipeline styles build on these families; real languages mix several of them.

flowchart TD
  P[Programming paradigms] --> IMP[Imperative]
  P --> DEC[Declarative]
  IMP --> PROC[Procedural / structured]
  IMP --> OOP[Object-oriented]
  IMP --> CONC[Concurrent and parallel]
  DEC --> FP[Functional]
  DEC --> LOGIC[Logic]
  DEC --> CONS[Constraint]
  DEC --> QUERY[Query languages: SQL]
  CONC --> EVT[Event-driven]
  CONC --> ACT[Actors / message passing]
  FP --> REACT[Reactive and dataflow]
  FP --> PIPE[Pipelines and streams]

1.3 Paradigm versus language versus framework

General model of expressing computation Formal syntax and semantics Haskell, Python, Rust A collection library

Structure and lifecycle supplied by a platform A web application framework Large-scale organization of a system Reusable design approach

A framework can encourage a paradigm, but it does not define the full paradigm.

1.4 Syntax and semantics

Syntax describes which programs are well-formed.

Semantics describes what a well-formed program means or does.

Static semantics includes rules checked before execution, such as type constraints.

Dynamic semantics describes behavior during evaluation.

Evaluation strategy describes when and how expressions are evaluated.

Runtime behavior includes execution, memory use, scheduling, exceptions, and interactions with the environment.

The syntax is an assignment statement with an addition expression. Its ordinary meaning is to evaluate the expression and bind or assign the result to x, subject to Python's name-binding rules.

x = 2 + 3

1.5 State, values, and effects

A value is a result such as 42, "hello", or a list.

State is information that can persist and change over time.

A side effect is an observable interaction beyond returning a value, such as writing a file, mutating shared state, or sending a network request.

Pure computation produces a result without observable side effects and with the same output for the same inputs, assuming the same semantics and no hidden dependencies.

Purity makes behavior easier to test and reason about, while effects are essential for real applications. The goal is to make effects explicit and manageable, not to eliminate all effects.

// Pure function
function area(width: number, height: number): number {
  return width * height;
}

// Effectful function
function announce(message: string): void {
  console.log(message);
}

1.6 How to compare paradigms

Compare them using:

Clarity of problem expression Ease of testing State and effect management Modularity and reuse Runtime and memory performance Tooling and ecosystem Interoperability and maintenance cost Try it: one task, several paradigms

The explorer below shows the same task written in different paradigms. Every output was produced by a real run of the code shown (the run environment is printed with each output).

paradigms

Knowledge check

Is Python a paradigm? No. It is a language that supports multiple paradigms.

Does declarative code have no execution steps internally? No. The runtime or engine still performs steps; the source expresses the desired result at a higher level.

Is functional programming the same as using map? No. It is a broader approach involving functions, composition, values, and effects.

Practice

Solve the same problem—filter passing students and compute their average—in an imperative style, a functional style, and a SQL query. Compare readability and edge-case behavior.

Quiz

? Which statement about paradigms and languages is accurate?
- Each language belongs to exactly one paradigm. :: Most mainstream languages support several paradigms.
+ A language can support several paradigms; a paradigm is a way of organising computation. :: Python, for example, supports procedural, object-oriented and functional styles.
- A framework defines a paradigm completely. :: A framework can encourage a paradigm, but it does not define it.
- Paradigms only differ in syntax. :: They differ in how state, control flow and effects are modelled — that is semantics, not just syntax.

? A function writes a log line and returns a value. Which description fits?
- It is pure because it returns a value. :: Returning a value does not make a function pure.
+ It has a side effect, so it is not pure. :: Writing a log line is an observable interaction beyond returning a value.
- It is declarative. :: Declarative describes a style of specifying results, not the presence of effects.
- It has no state. :: Whether it has state is a separate question; the log write is the effect.

? What do "syntax" and "semantics" each describe? (select all that apply)
+ Syntax: which programs are well-forme
…