In informatica un paradigma di programmazione è uno stile fondamentale di programmazione.
È un insieme di strumenti concettuali forniti dal linguaggio ed una serie di best practice da usare per la stesura del codice sorgente di un programma.
I paradigmi di programmazione si differenziano nei concetti e nelle astrazioni usate per rappresentare gli elementi di un programma.
È possibile identificare un processo ereditario tra i vari paradigmi e quindi un albero genealogico.
Linguaggi di programmazione
Ogni linguaggio di programmazione viene sviluppato seguendo una idea in qualche modo riconducibile ad un particolare paradigma.
Esistono linguaggi considerati puri e linguaggi impuri cioè che non seguono in maniera stretta (pura) il paradigma.
Alcuni linguaggi si ispirano a due o più paradigmi: linguaggi multiparadigma.
Paradigmi più comuni
Esistono molti paradigmi di programmazione che sono stati pensati e sviluppati nel tempo, alcuni hanno avuto più successo di altri.
Il successo di una pratica di programmazione è indipendente dalla sua bontà intrinseca, ma deve essere fatto ricadere in più fattori:
momento storico
capacità di chi la usa.
richieste industriali
visione del futuro.
management
Programmazione procedurale
~1960
Blocchi di codice esecutivo identificati da un nome.
I blocchi sono racchiusi in un ambito di visibilità da delimitatori.
I blocchi possono avere variabili e parametri che sono persi all'uscita.
I blocchi possono avere valori in uscita.
Subroutine, procedure, funzioni.
Fortran, COBOL.
I linguaggi moderni permettono la scrittura di procedure e funzioni (alcuni come il Pascal le distinguono, altri come il C no).
Programmazione strutturata
~1960/1970
È la base per altri tipi di programmazione imperativa (es: Object Oriented Programming (OOP)).
Critica del goto e spaghetti code.
Nata basandosi sul teorema di Corrado Böhm e Giuseppe Jacopini che afferma come si possa scrivere un programma senza goto solo con delle strutture di controllo.
Strutture di controllo: sequenza (una istruzione dopo l'altra, sequenza imperativa), selezione (if-then-else, operatori ternari ?:, if a tre vie del FORTRAN 2, case/switch), ciclo (while-do, do-until, for-do).
Sviluppo della applicazione di algoritmi alla programmazione.
Linguaggi tipizzati.
Pascal, Ada, Algol, C.
Programmazione modulare
~1970
Suddivisione del programma in parti chiamate moduli.
I moduli sono indipendenti.
I moduli sono opachi internamente e possono idealmente vivere a se stanti.
I moduli hanno una interfaccia per comunicare con l'esterno.
Modula, Modula-2, Oberon, CLU, Ada, Pascal.
Linguaggi tipizzati.
La maggior parte dei linguaggi moderni la permettono in qualche maniera.
Programmazione funzionale 1
~1970
Incentrata sul concetto di funzione nel senso matematico del termine. (dominio (x), codominio (y) e relazione (f): y = f(x)).
Le funzioni sono valori.
Trasparenza referenziale (assenza di effetti collaterali, lo stato esterno della funzione non è alterato. Il valore di ritorno dati gli stessi parametri è garantito in qualunque caso).
La mancanza di effetto collaterale la rende automaticamente thread-safe.
Ricorsività e funzioni ricorsive, in particolare la tail recursion che limita l'allocazione dello stack ed il recupero del blocco esecutivo.
Funzioni di ordine superiore (high-order), le funzioni possono prendere funzioni come parametri e restituire funzioni come risultato).
Programmazione funzionale 2
Funzioni anonime, closure.
Tipi parametrici.
Generalized and extended algebraic data type, permette di creare tipi compositi, tipi varianti.
Currying, funzione con parametri multipli in funzioni con parametri singoli (possibili le partial application o funzioni semiprecalcolate).
Pattern matching, switch/case on steroids.
Programmazione funzionale 3
Decomposizione di strutture complesse.
List/set/for comprehension, map, filter, reduce, collect, ciclo for parametrico.
Strict o lazy, computazione dei valori e parametri prima della funzione o solo a richiesta.
Linguaggi tipizzati, inferenza di tipo, dinamici, puri (con Monadi), impuri.
Lisp, Clojure, Scheme, Racket, Scala, Standard ML, OCaml, F#, Erlang, Elixir, Haskell, Dylan, Ruby (in parte), Python (in parte).
In forte ascesa. Programmazione parallela più sicura. Reactive programming.
Programmazione object oriented 2
~1980
Estensione della programmazione modulare.
Definizione di oggetti opachi in grado di interagire tramite messaggi o funzioni (metodi).
Incapsulamento (separazione tra interfaccia ed implementazione).
Ereditarietà singola o multipla (creazione di gerarchie genitore e figlio - visibilità dei campi: pubblica o privata, protetta, pubblicata (Object Pascal property - Java Beans)).
Polimorfismo, la possibilità di utilizzare una classe dalla sua interfaccia, intercambiabilità di classi con identica interfaccia.