L'astrazione, in informatica, è l'applicazione del metodo logico di astrazione nella strutturazione della descrizione dei sistemi informatici complessi, per facilitarne la progettazione e manutenzione o la stessa comprensione.
Descrizione generale La pratica consiste nel presentare il sistema, ad esempio un pezzo di codice sorgente o uno scambio di trasmissioni di dati, in maniera ridotta ai soli dettagli considerati essenziali all'interesse specifico, ad esempio raggruppando il codice in una funzione o formalizzando un protocollo di comunicazione.
Indica quanto il codice scritto in un linguaggio di programmazione si distacca dalle istruzioni in linguaggio macchina che a esso corrisponderanno dopo l'operazione di compilazione. Delle istruzioni scritte in Java, per esempio, sono molto più vicine al linguaggio comprensibile all'uomo piuttosto che a quello comprensibile dalla macchina (alto livello di astrazione). Viceversa delle istruzioni scritte in Assembly sono abbastanza vicine (ma non uguali) alle istruzioni in formato comprensibile alla macchina (basso livello di astrazione).
La seguente definizione di astrazione aiuta a capire come questo termine viene applicato all'informatica:
Il concetto è originato mediante l'analogia con l'astrazione in matematica. La tecnica matematica dell'astrazione comincia con definizioni matematiche; Ad esempio, sia in Informatica che in Matematica i numeri sono concetti nei linguaggi di programmazione. I dettagli dell'implementazione dipendono dall'hardware e dal software, ma non è una restrizione, poiché il concetto di numero in Informatica è ancora basato sul concetto matematico.
In programmazione, l'astrazione può essere applicata a strutture di controllo o a strutture di dati. L'astrazione di strutture di controllo implica l'uso di sottoprogrammi e di altri concetti relativi a queste. Le strutture di dati astratte permettono di maneggiare i dati in maniere significanti.
Il fatto che i programmatori utilizzino le astrazioni quando possibile per evitare duplicazioni (solitamente di codice) è noto come principio di astrazione.
L'informatica prevalentemente opera indipendentemente dal mondo reale: l'hardware implementa un modello di computazione che è intercambiabile con altri, il software è strutturato in architetture per permettere all'uomo di creare enormi sistemi concentrandosi su pochi problemi alla volta. Queste architetture sono fatte da precise scelte di astrazioni.
Una forma principale di astrazione in Informatica è l'astrazione dei linguaggi: nuovi linguaggi artificiali vengono sviluppati per esprimere specifici aspetti di un sistema. I linguaggi di modellazione aiutano nell'organizzazione. I linguaggi di programmazione possono essere processati con un computer. Un esempio di questo processo di astrazione è lo sviluppo di linguaggi di programmazione dal linguaggio macchina, al linguaggio assembly e ai linguaggi ad alto livello. Ognuno di questi stadi può essere utilizzato come base per lo stadio successivo.
In un linguaggio di programmazione, alcune funzioni permettono al programmatore di creare nuove astrazioni. Queste includono le subroutine, i moduli e le componenti software.
Alcune astrazioni provano a limitare la larghezza dei concetti di cui un programmatore ha bisogno nascondendo completamente le astrazioni sulle quali a loro volta sono costruite. Joel Spolsky, comunque, afferma che nessuna astrazione può completamente nascondere tutti i dettagli: a ogni modo, questo non nega l'utilità dell'astrazione. Alcune astrazioni sono designate per interagire con altre, ad esempio un linguaggio di programmazione potrebbe contenere una FFI (Foreign Function Interface) per effettuare chiamate a linguaggi di basso livello.
Caratteristiche dei linguaggi Linguaggi di programmazione Diversi linguaggi di programmazione offrono diversi tipi di astrazione, in base alle applicazioni destinate per il linguaggio. Ad esempio:
Nei linguaggi di programmazione orientati agli oggetti (, OOP) come il C++ o Java, il concetto di astrazione è diventato un'istruzione dichiarativa utilizzando la parola chiave in C++, e in Java. Dopo questa dichiarazione, è compito del programmatore implementare una classe per istanziare l'oggetto della dichiarazione. I linguaggi di programmazione funzionale solitamente espongono astrazioni relative a funzioni, come le lambda astrazioni e le funzioni di ordine superiore. Il linguaggio Linda permette l'astrazione di alcuni concetti come quello di server per facilitare la programmazione distribuita.
Metodi di specificazione Gli analisti hanno sviluppato diversi metodi per specificare formalmente sistemi software. Alcuni metodi conosciuti includono:
Metodi basati su modelli astratti (VDM, Z); Tecniche Algebriche (Larch, CLEAR, OBJ, ACT ONE); Tecniche basate su processi (LOTOS, SDL, Estelle); Tecniche basate su tracce (SPECIAL, TAM); Tecniche basate sulla conoscenza (Refine, Gist).
Linguaggi di specificazione I linguaggi di specificazione spesso fanno affidamento su un tipo di astrazione o un altro, visto che le specificazioni sono tipicamente definite all'inizio di un progetto (a un livello più astratto). Il linguaggio UML, ad esempio, permette di definire classi astratte, che rimangono astratte durante l'architettura e la fase di specificazione del progetto.
Strutture di controllo astratte I linguaggi di programmazione permettono astrazioni di strutture di controllo come uno dei loro compiti principali. I computer eseguono operazioni a un livello molto basso, ad esempio muovendo alcuni bit da una locazione di memoria a un'altra, producendo la somma di due sequenze di bit. I linguaggi di programmazione permettono che questo sia fatto a un livello più alto. Consideriamo ad esempio questo codice scritto in Pascal: . Per un uomo, questo sembra un semplice e ovvio calcolo (uno più due fa tre, per cinque fa quindici). Ebbene, i passaggi a basso livello necessari per arrivare a questa conclusione, ritornare il valore "15" e assegnarlo alla variabile a, sono più complessi. I valori devono essere convertiti in rappresentazione binaria (un processo più complicato di quanto si possa pensare) e i calcoli devono essere scomposti (dal compilatore o dall'interprete) in istruzioni assembly (molto meno intuitive al programmatore). Alla fine, assegnare il valore risultante "15" alla variabile chiamata a, in modo che possa essere utilizzata successivamente, implica altri passaggi "dietro le quinte", come cercare la locazione di memoria dove inserire il valore "15", e così via.
Senza questo tipo di astrazione, un programmatore dovrebbe specificare tutti i passaggi "registro/livello binario" anche solo per aggiungere o moltiplicare due numeri e assegnare il risultato a una variabile. Questo tipo di compito ha due serie conseguenze negative: Forza il programmatore a ripetere costantemente le stesse banali e semplici istruzioni ogni volta che ce ne sia bisogno Forza il programmatore a programmare per uno specifico set di hardware e istruzioni (si parla quindi di linguaggi legati alla macchina)
Programmazione strutturata La programmazione strutturata implica la suddivisione di complessi compiti di un programma in pezzi più piccoli con lo scopo di semplificarli ed evitare "effetti collaterali".
In un programma semplice, questo potrebbe servire per assicurarsi che un ciclo abbia un singolo o più ovvi punti di uscita e, dove possibile, per assicurarsi che funzioni e procedure ne abbiano solo uno.
In un sistema più grande, invece, potrebbe implicare la suddivisione di compiti complessi in tanti moduli diversi. La programmazione orientata agli oggetti (OOP) ha abbracciato ed esteso questo concetto.
Strutture di dati astratte Le strutture di dati astratte rinforzano una chiara separazione tra le proprietà astratte di un tipo di dati e i dettagli concreti della sua implementazione. Le proprietà astratte sono quelle che sono visibili a colui che fa uso del tipo di dati – l'interfaccia del tipo di dati – mentre l'implementazione concreta è completamente mantenuta privata, e ovviamente può cambiare per implementare migliorie di efficienza nel tempo. L'idea è che questi cambiamenti non devono avere alcun impatto, e non devono creare differenze nell'aspetto astratto.
Per esempio, si potrebbe definire un tipo di dato astratto chiamato tavola di ricerca (), che associa in modo univoco chiavi a valori, e nella quale è possibile ottenere il valore desiderato digitando la chiave corrispondente. Una tavola di ricerca del genere può essere implementata in vari modi, ad esempio con una hash table (in italiano tabella hash o mappa hash).
I linguaggi che implementano le strutture di dati astratte includono Ada e Modula-2.
Astrazione nella programmazione orientata agli oggetti Nella teoria della programmazione orientata agli oggetti, l'astrazione implica la facilità di definire oggetti che rappresentino "attori" che possono svolgere lavori, riportare e cambiare il loro stato, e comunicare con gli altri oggetti nel sistema. Il termine incapsulamento si riferisce al nascondere i dettagli di stato, ma estendere il concetto di tipo di dato dai primi linguaggi di programmazione, e standardizzare il modo in cui i diversi tipi di dati interagiscono, è l'inizio dell'astrazione. Si parla di polimorfismo quando l'astrazione consente a oggetti di diverso tipo di venire sostituiti. Si parla di ereditarietà quando più tipi o classi vengono strutturati per semplificare un set complesso di relazioni.
Vari linguaggi di programmazione orientata agli oggetti offrono simili agevolazioni per l'astrazione, per supportare tutti insieme una strategia generale di polimorfismo, che implica la sostituzione di un tipo in uno che abbia lo stesso ruolo o uno simile.
Common Lisp Object System (conosciuto anche come CLOS) e self hanno un grande utilizzo del polimorfismo. Oggetti individuali e funzioni sono astratti più flessibilmente in modo da adattarsi meglio all'eredità condivisa funzionale del Lisp.
Anche se alcuni linguaggi offrono strategie alternative per ottenere la stessa astrazione, fondamentalmente non modificano il bisogno di supportare nomi astratti nel codice. Tutta la programmazione conta sull'abilità di astrarre verbi, funzioni, strutture di dati, nomi e processi.
Consideriamo ad esempio un frammento di codice Java per rappresentare alcuni comuni "animali" di fattoria a un livello di astrazione tale da simulare i più semplici aspetti della loro fame e del nutrimento. Definiamo una classe Animale per rappresentare entrambi gli stati dell'animale e le sue funzioni:
public class Animale extends EssereVivente { private Luogo loc; private double riserveEnergia;
boolean affamato()
return riserveEnergia < 2.5;
void mangia(Cibo f)
//Mangia il cibo riserveEnergia += f.getCalorie();
void muoviti (Luogo l)
//Si muove verso un altro luogo loc = l;
Con la definizione di cui sopra, si potrebbero creare oggetti di tipo Animale e chiamare metodi del genere:
ilMaiale = new Animale(); laMucca = new Animale(); if (ilMaiale.affamato()) { ilMaiale.mangia(avanzi); } if (laMucca.affamato()) { laMucca.mangia(erba); } laMucca.muoviti(fienile);
Nell'esempio sopra, la classe Animale è un'astrazione usata al posto di un vero animale, EssereVivente è un'ulteriore astrazione (in questo caso una generalizzazione) di Animale.
Se viene richiesta una gerarchia più differenziata di animali – per differenziare, diciamo, quelli che producono latte da quelli che non producono niente e non la carne dopo che hanno finito di vivere – può esserci un livello intermedio di astrazione, come "Animali Lattiero-Caseari" (mucche o capre) che mangiano cibi per produrre buon latte, e "Animali" (suini e manzi) che mangiano cibi per dare la migliore qualità di carne.