Skip to content

HowProgrammingWorks/Paradigms

Repository files navigation

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

  1. Control Flow
  • Statements, algorithm steps
    constuser=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);
  1. Identifiers
  • Assignment statement
    leta=10;constb=20;a=a+b;
  • Call arguments
    ((a,b)=>a+b)(5,3);
  • Only callable
    consta=()=>10;constb=()=>20;constsum=(x,y)=>()=>x()+y();constc=sum(a,b);
  1. State
  • Mutable state and form
    constcounter={value: 0};counter.value+=1;
  • Mutable form
    counter.ready=true;
  • Immutable state
    constpoint=Object.freeze({x: 10,y: 20});constmove=(p)=>({ x, y })=>({x: p.x+x,y: p.y+y});constmoved=move(point)({x: 3,y: 7});
  • Copy-on-write
    constp1={x: 10,y: 20};constp2=Object.create(p1);p2.x=7;
  • Stateless functions
    consttwice=(x)=>x*2;
  1. Context
  • Objects
    constpoint={x: 10,y: 20,move(dx,dy){this.x+=dx;this.y+=dy;}};
  • Records
    constpoint={x: 10,y: 20};constmove=(p,d)=>{p.x+=d.x;p.y+=d.y;};
  • Closures
    constcreateCounter=(count=0)=>()=>++count;
  • Boxing
    constprimitive=42;constinstance=newNumber(42);constboxed=Box.of(42);
  • Containers
    Box.of(42);Either.right(42);Promise.resolve(42);letmaybe: number|null=42;typePair={a?: number;b?: number};typeOption<T>={kind: 'some'; value: T}|{kind: 'none'}; std::optional<int>; std::tuple<int>; std::reference_wrapper<int>;Nullable<int>maybe=42;newStrongBox<int>(value);Tuple.Create(myIntValue);
  • Modules
    constcache=newMap();exportconstget=(key)=>cache.get(key);exportconstset=(key,value)=>cache.set(key,value);
  1. Branching
  • Conditional statement
    if(x>0){console.log('positive');}elseif(x<0){console.log('negative');}else{console.log('zero');}
  • Conditional expression
    constsign=x>0 ? 'positive' : x<0 ? 'negative' : 'zero';
  • Guards
    constprocess=(x)=>{if(x===null)returnnull;if(x<0)returnnull;returnx*2;};
    func process(_ x:Int?)->Int?{guardlet v = x else{returnnil}guard v >=0else{returnnil}return v *2}
  • Pattern matching
    fnprocess(x:Option<i32>) -> Option<i32>{match x {None => None,Some(v)if v < 0 => None,Some(v) => Some(v *2),}}
    constmatch=(variant,handlers)=>handlers[variant.tag](variant);match({tag: 'point',x: 10,y: 20},{point: ({ x, y })=>`(${x}, ${y})`,circle: ({ r })=>`radius: ${r}`});
  1. Iteration
  • Loops (for, while, do)
    for(leti=0;i<10;i++)console.log(i);while(condition){/* steps */}do{/* steps */}while(condition);
  • Recursion calls (incl. tail recursion)
    constfactorial=(n)=>n<=1 ? 1 : n*factorial(n-1);consttailFact=(n,acc=1)=>n<=1 ? acc : tailFact(n-1,n*acc);
  • Iterators / Generators
    function*range(start,end){for(leti=start;i<end;i++)yieldi;}for(constnofrange(0,5))console.log(n);
  • Streams
    constres=awaitfetch('/api/endpoint');forawait(constchunkofres.body)console.log(newTextDecoder().decode(chunk));
    For Node.js
    constr=Readable.from(gen());
  1. Instantiation
  • Operator new
    constpoint=newPoint(10,20);
  • Creational patterns like Factory, Builder
    constp=Point.create(10,20);constq=awaitQuery.select('cities').where({country: 10}).order('population');
  • Closures
    constp=createPoint(10,20);constq=awaitselect('cities').where({country: 10}).order('population');
  • Containers
    classMaybe<T=unknown>{constructor(value?: T);getvalue(): T|undefined;isEmpty(): boolean;match<R>(some: (value: T)=>R,none: ()=>R): R;}
  • Cloning
    constclone1={ ...original};constclone2=Object.assign({},original);constclone3=structuredClone(original);
  • Pattern GOF:Flyweight
  1. Inheritance
  • Classes
    classSavingAccountextendsAccount
  • Interfaces (implements)
    classCursorimplementsIterator<Account>
  • Prototype programming
    constlogger=Object.create(console,{log: {value: (s)=>process.write(s)}});
  • Mixins
    constlogger={};logger.log=console.log;Object.assign(logger,{info: ()=>{}});
  • Structural composition
    classLogger{constructor(name){this.stream=fs.createWriteStream(name);}}
  • Partial/Curry
    constadd=(a,b)=>a+b;{constadd5=(b)=>add(5,b);}constcurriedAdd=(a)=>(b)=>a+b;{constadd5=curriedAdd(5);}{constadd5=add.bind(add,null,5);}
  • Traits
    pubtraitToJson{fnto_json(&self) -> String;}pubstructUser{pubid:u32,pubname:String,}implToJsonforUser{fnto_json(&self) -> String{format!(r#"{{"id":{},"name":"{}"}}"#,self.id,self.name)}}
    TypeScript alternative
    interfaceToJson{toJson: ()=>string}classUserimplementsToJson{readonlyid: numberreadonlyname: stringconstructor(id: number,name: string){this.id=idthis.name=name}toJson=(): string=>{return`{"id":${this.id},"name":"${this.name}"}`}}
  1. Primitive values
  • Scalars
    constnumber=42;
  • Boxing
    constnumber=42;constboxed=Object(number);constunboxed=Number(boxed);
  • Value Objects
    classInteger{privatereadonlyvalue: number;// implement constructor and math operations}consta=newInteger(7);constb=newInteger(3);constc=a.add(b);
  • Containers
  1. Asynchronity
  • Callback
    constfetchData=(callback)=>setTimeout(()=>callback('data'),100);fetchData((result)=>console.log(result));
  • Promise
    constfetchData=()=>Promise.resolve('data');fetchData().then((result)=>console.log(result));
  • Async/await
    constdata=awaitfetchData();
  • Future, Task
    constfs=require('node:fs');constfuturify=(fn)=>(...args)=>newFuture((reject,resolve)=>fn(...args,(error,result)=>error ? reject(error) : resolve(result)),);constreadFuture=futurify(fs.readFile);constwriteFuture=futurify(fs.writeFile);readFuture('future.js','utf8').map((text)=>text.toUpperCase()).chain((text)=>writeFuture('future.md',text)).fork((error)=>console.error('FS error:',error),()=>console.log('Done'),);
  • Async compose
    constprepareReport=pipe(read,parse,calculate,render);constchecks=parallel(checkBalance,checkAvailability,checkFraud);
  • Observer (EventEmitter, EventTarget, Signal)
  • Streams and other abstractions
  1. Purity
  • Pure functions
    constadd=(a,b)=>a+b;constsquare=(x)=>x*x;
  • Functions with side effects
    letcounter=0;constincrement=()=>++counter;
  • IO monads
  1. First-class citizens
  • Higher-order functions
  • Passing behaviour as object
  1. Evaluation Flow
  • Function composition
  • Nested calls
  • Pipeline |>
    constresult=input|>validate|>transform|>process;
  1. Point style
  • Point-free style: const f = compose(g, h)
  • Point style: const f = (x) => g(h(x))
  1. Dependencies
  • Pass all dependencies as arguments
    constcreateService=(db,logger)=>{/* implementation */};
  • Dependency injection
    classService{constructor(db,logger){this.db=db;this.logger=logger;}}
  • Global namespaces
    constuser=application.auth.getUser('marcus');
  • Service locators
    constServiceLocator={services: {},register(name,service){this.services[name]=service;},get(name){returnthis.services[name];}};
  • Module systems
  1. Structural Control (see Branching)
  • Nested if/else conditionals
    if(x>0){if(x>10){console.log('large');}else{console.log('small');}}else{console.log('negative');}
  • Pattern matching
  • Guards
  1. Error handling
  • Total functions
    constsafeDivide=(a,b)=>a/b;
  • Throwing exceptions
    constdivide=(a,b)=>{if(b===0)thrownewError('Division by zero');returna/b;};
  • Error codes
  • Return null, undefined, NaN
  • Null objects
    constnullUser={name: 'Guest',isAuthenticated: false,login: ()=>{}};constuser=getUser()??nullUser;
  • Option / Either / Result / Promise
    classEither<L=unknown,R=unknown>{constructor(params: {left?: L|null;right?: R|null});staticleft<L>(value: L): Either<L,null>;staticright<R>(value: R): Either<null,R>;getleft(): L|null;getright(): R|null;isLeft(): boolean;isRight(): boolean;map<U>(fn: (value: R)=>U): Either<L,U>;match<T>(leftFn: (left: L)=>T,rightFn: (right: R)=>T): T;}
  1. Stability of Effects
  • Idempotent operations new Set().add(3).add(3)
  • Order-sensitive operations ((a) => (a.push(3), a.push(7), a))([])
  • Commutative / associative operations add(a, b) === add(b, a)
  1. Semantic Transparency
  • Non-Referential transparent
    classCounter{ #value =0;inc=()=>(++this.#value);}
  • Referential transparency
    classCounter{ #value;constructor(value=0){this.#value =value;}inc=()=>newCounter(this.#value +1);value=()=>this.#value;}
  • Equational reasoning
    constf=(x)=>x*2;constg=(x)=>x+1;// f(g(x)) === (x + 1) * 2 === 2x + 2// Can reason about code as equations
  • Deterministic evaluation
    constpure=(x)=>x*2;constimpure=()=>Math.random();
  • No hidden state
  1. Caching
  • Hash-table caching
    constcache=newMap();constget=(key)=>cache.get(key);constset=(key,value)=>cache.set(key,value);
  • Memoization
    constfib=memoize((n)=>n<=1 ? n : fib(n-1)+fib(n-2));
  1. Resource Control
  • Manual destruction
    classResource{constructor(){this.handle=acquire();}dispose(){release(this.handle);}}constresource=newResource();try{// use resource}finally{resource.dispose();}
  • RAII / disposables
    constusing=(resource,fn)=>{try{returnfn(resource);}finally{resource.dispose();}};
    New JavaScript Disposables: Symbol.dispose, Symbol.asyncDispose
    constmain=async()=>{awaitusinglogger=awaitnewLogger('output.log');awaitlogger.log('Open');awaitlogger.log('Do something');};
  • Region-based allocation
    constwithRegion=(fn)=>{constregion=[];try{returnfn(region);}finally{region.forEach(cleanup);}};
  • Ownership allocate/free
  1. Concurrency Model
  • Shared-memory concurrency
  • Stateless functions
  • Message passing (Actor model)
  • Transactional memory
  • Locking, Semaphor, Mutex
  1. Data Ownership
  • Copy semantics
  • Move semantics
  • Shared vs exclusive references
  1. Granularity
  • One-liners
  • Long code blocks
  • Moderate granularity

Memes

constgetTomorrowDate=()=>{consttimeout=86400000;returnnewPromise((resolve)=>{setTimeout(()=>{resolve(newDate());},timeout)});};
constCoin=(v)=>({map: (f)=>Coin(f(v))});constflip=()=>crypto.getRandomValues(newUint8Array(1))[0];Coin(flip()).map((r)=>(r&1 ? '🪙' : '💩')).map(console.log);
constfindMeaningOfLife=()=>{constoffset=0;constdelay=Infinity;returnnewPromise((resolve)=>{setTimeout(()=>{resolve(42+offset);},delay);});};
classComing{constructor(){returnnewPromise((resolve)=>setTimeout(()=>{resolve(this);},DAY_OF_JUDGMENT-Date.now()));}}constsecondComing=awaitnewComing();
((<Fextends()=>void>(Function: F={}asF)=>Function())())
classFuture{constructor(){const{name: key}=this.constructor;constvalue=void[].length;thrownewError(`${key} is ${value}`);}}newFuture();

About

Programming Paradigms Comparison

Resources

License

Stars

Watchers

Forks