Paradigms
Programming Paradigms Comparison
Install / Use
/learn @HowProgrammingWorks/ParadigmsREADME
Programming Paradigms Comparison
Paradigms
- Imperative Programming
- Characteristics: statements mutate program state directly (let, loops, assignments)
- Architecture Influence: stateful services, command-driven architecture
- Procedural Programming
- Characteristics: step-by-step, linear control flow, mutable state
- Architecture Influence: transaction script, single responsibility units, shallow call graphs
- Object-Oriented Programming
- Characteristics: classes/objects, encapsulation, inheritance, polymorphism
- Architecture Influence: DDD, layered architecture, clean architecture, hexagonal
- Prototype-based Programming
- Characteristics: objects inherit from other objects, delegation over inheritance
- Architecture Influence: flexible object composition, dynamic plugin systems
- Functional Programming
- Characteristics: pure functions, immutability, no shared state, higher-order functions, pattern matching, curry, single argument functions, composition
- Architecture Influence: functional pipelines, stateless services, async stream processing
- Closure-based Programming
- Characteristics: functions hold private state via closures, encapsulated behavior
- Architecture Influence: lightweight encapsulation, reactive units, factory patterns
- Actor Model
- Characteristics: message passing, no shared memory, isolated context, transparent concurrency units
- Architecture Influence: distributed systems, concurrency-safe services, microservices
- Structural Programming
- Blocks, No goto
- Declarative Programming
- Characteristics: emphasizes what over how, side-effect free, high-level code, DSLs, self-descriptive
- Architecture Influence: configuration-over-code, rule engines
- Contract programming
- Characteristics: difine contracts
- Architecture Influence: stable and clear, self-descriptive
- Reactive Programming
- Characteristics: observable streams, event-driven, push-based, backpressure-aware
- Architecture Influence: UIs, data stream processing, feedback loops, real-time pipelines
- Finite-State Machines / Automata
- Characteristics: explicit states, transitions, events, deterministic flow
- Architecture Influence: workflow engines
- Metaprogramming
- Characteristics: code generation, reflection, macros, introspection
- Architecture Influence: high flexibility, scaffolding
Basic Ideas
- Control Flow
- Statements, algorithm steps
const user = read({ id: 15 }); if (user.name === 'marcus') { console.log(user.age); } - Expression
({ id }) => (fn) => fn({ id, name: 'marcus', age: 42 }) ({ id: 15 })(({ name, age }) => name === 'marcus' ? (log) => log(age) : () => {}) (console.log); - Do-notation
Do({ id: 15 }) .chain(({ id }) => ({ id, name: 'marcus', age: 42 })) .chain(({ name, age }) => name === 'marcus' ? (log) => log(age) : () => {}) .run()(console.log); - Declarative style
execute({ read: { id: 15 }, then: { match: { name: 'marcus' }, success: { effect: { log: 'age' } }, fail: { effect: 'noop' }, }, })(reader, console.log)(); - Pipeline operator
(({ id: 15 }) |> read |> (({ name, age }) => name === 'marcus' ? (log) => log(age) : () => {}) )(console.log); - Pipe (composition)
pipe( { id: 15 }, read, ({ name, age }) => name === 'marcus' ? (log) => log(age) : () => {} )(console.log);
- Identifiers
- Assignment statement
let a = 10; const b = 20; a = a + b; - Call arguments
((a, b) => a + b)(5, 3); - Only callable
const a = () => 10; const b = () => 20; const sum = (x, y) => () => x() + y(); const c = sum(a, b);
- State
- Mutable state and form
const counter = { value: 0 }; counter.value += 1; - Mutable form
counter.ready = true; - Immutable state
const point = Object.freeze({ x: 10, y: 20 }); const move = (p) => ({ x, y }) => ({ x: p.x + x, y: p.y + y }); const moved = move(point)({ x: 3, y: 7 }); - Copy-on-write
const p1 = { x: 10, y: 20 }; const p2 = Object.create(p1); p2.x = 7; - Stateless functions
const twice = (x) => x * 2;
- Context
- Objects
const point = { x: 10, y: 20, move(dx, dy) { this.x += dx; this.y += dy; } }; - Records
const point = { x: 10, y: 20 }; const move = (p, d) => { p.x += d.x; p.y += d.y; }; - Closures
const createCounter = (count = 0) => () => ++count; - Boxing
const primitive = 42; const instance = new Number(42); const boxed = Box.of(42); - Containers
Box.of(42); Either.right(42); Promise.resolve(42); let maybe: number | null = 42; type Pair = { a?: number; b?: number }; type Option<T> = { kind: 'some'; value: T } | { kind: 'none' }; std::optional<int>; std::tuple<int>; std::reference_wrapper<int>; Nullable<int> maybe = 42; new StrongBox<int>(value); Tuple.Create(myIntValue); - Modules
const cache = new Map(); export const get = (key) => cache.get(key); export const set = (key, value) => cache.set(key, value);
- Branching
- Conditional statement
if (x > 0) { console.log('positive'); } else if (x < 0) { console.log('negative'); } else { console.log('zero'); } - Conditional expression
const sign = x > 0 ? 'positive' : x < 0 ? 'negative' : 'zero'; - Guards
const process = (x) => { if (x === null) return null; if (x < 0) return null; return x * 2; };func process(_ x: Int?) -> Int? { guard let v = x else { return nil } guard v >= 0 else { return nil } return v * 2 } - Pattern matching
fn process(x: Option<i32>) -> Option<i32> { match x { None => None, Some(v) if v < 0 => None, Some(v) => Some(v * 2), } }const match = (variant, handlers) => handlers[variant.tag](variant); match({ tag: 'point', x: 10, y: 20 }, { point: ({ x, y }) => `(${x}, ${y})`, circle: ({ r }) => `radius: ${r}` });
- Iteration
- Loops (for, while, do)
for (let i = 0; i < 10; i++) console.log(i); while (condition) { /* steps */ } do { /* steps */ } while (condition); - Recursion calls (incl. tail recursion)
const factorial = (n) => n <= 1 ? 1 : n * factorial(n - 1); const tailFact = (n, acc = 1) => n <= 1 ? acc : tailFact(n - 1, n * acc); - Iterators / Generators
function* range(start, end) { for (let i = start; i < end; i++) yield i; } for (const n of range(0, 5)) console.log(n); - Streams
For Node.jsconst res = await fetch('/api/endpoint'); for await (const chunk of res.body) console.log(new TextDecoder().decode(chunk));const r = Readable.from(gen());
- Instantiation
- Operator
newconst point = new Point(10, 20); - Creational patterns like Factory, Builder
const p = Point.create(10, 20); const q = await Query.select('cities').where({ country: 10 }).order('population'); - Closures
const p = createPoint(10, 20); const q = await select('cities').where({ country: 10 }).order('population'); - Containers
class Maybe<T = unknown> { constructor(value?: T); get value(): T | undefined; isEmpty(): boolean; match<R>( some: (value: T) => R, none: () => R ): R; } - Cloning
const clone1 = { ...original }; const clone2 = Object.assign({}, original); const clone3 = structuredClone(original); - Pattern GOF:Flyweight
- Inheritance
- Classes
class SavingAccount extends Account - Interfaces (
implements)class Cursor implements Iterator<Account> - Prototype programming
const logger = Object.create(console, { log: { value: (s) => process.write(s) } }); - Mixins
const logger = {}; logger.log = console.log; Object.assign(logger, { info: () => {} }); - Structural composition
class Logger { constructor(name) { this.stream = fs.createWriteStream(name); } } - Partial/Curry
const add = (a, b) => a + b; { const add5 = (b) => add(5, b); } const curriedAdd = (a) => (b) => a + b; { const add5 = curriedAdd(5); } { const add5 = add.bind(add, null, 5); } - Traits
TypeScript alternativepub trait ToJson { fn to_json(&self) -> String; } pub struct User { pub id: u32, pub name: String, } impl ToJson for User { fn to_json(&self) -> String { format!(r#"{{"id":{},"name":"{}"}}"#, self.id, self.name) } }interface ToJson { toJson: () => string } class User implements ToJson { readonly id: number readonly name: string constructor(id: number, name: string) { this.id = id this.name = name } toJson = (): string => { return `{"id":${this.id},"name":"${this.name}"}` } }
- Primitive values
- Scalars
const number = 42; - Boxing
const number = 42; const boxed = Object(number); const unboxed = Number(boxed); - Value Objects
class Integer { private readonly value
