Il computer funziona eseguendo programmi, che sono sequenze di istruzioni logico-matematiche semplici. La programmazione consiste nel ridurre la soluzione di un problema complesso ad una sequenza di queste istruzioni semplici.
I programmi, come eseguiti dal computer, sono sequenze di valori binari, che pilotano direttamente i circuiti dell'hardware e la CPU ha circuiti capaci di eseguire solo le funzioni piu' elementari, eventuali istruzioni complesse sono interpretate (cioe' tradotte) e ridotte ad una sequenza di istruzioni elementari da un micro-programma che sta nella CPU stessa. Questi microprogrammi erano comuni nelle architetture CISC, come i VAX, mentre non sono usati nelle architetture RISC. Le CPU Intel dei PC accettano istruzioni complesse, ed hanno circuiti appositi per la loro scomposizione in istruzioni semplici, in modo che possano essere eseguite da un core RISC. Il fatto se le istruzioni siano interpretate da microprogrammi o no e' trasparente al programmatore, che si occupa di quali istruzioni la CPU accetti, piu' di come le tratti internamente.
Tutti i dati sono rappresentati nel computer come sequenze di 0 ed 1,
queste sequenze devono essere trattate in modo diverso a seconda del loro
significato, a seconda cioe' che contengano numeri interi, caratteri, istruzioni od altro.
Il significato non e' contenuto nel dato, nel senso che non e' scritto insieme
alla sequenza di 0 ed 1, ma la stessa sequenza potrebbe essere interpretata in
modo diverso. E' il programma che deve sapere che tipo di dato e' contenuto in
una posizione di memoria ed interpretarla nel modo corretto.
Quando si scrive un programma e' quindi importante specificare bene quali siano i tipi
di dati su cui si opera, i principali tipi di dato sono:
Le istruzioni per la CPU sono costituite da un codice numerico, che indica cosa eseguire e da uno o piu' operandi che contengono indirizzi di memoria o registri su cui l'istruzione Opera. Le istruzioni sono dei seguenti tipi:
Dal punto di vista del programmatore la CPU esegue essenzialmente istruzioni di questo tipo, in piu' c'e' il calcolo degli indirizzi, la gestione degli interrupt ed altre funzioni di cui pero' il programmatore si accorge poco.
Un altro elemento importante nella logica della programmazione sono le routines. Le routines ( o funzioni) sono parti di programma riutilizzabili, che hanno la stessa logica delle funzioni di tipo matematico: gli si danno dei valori in input (argomenti) e loro restituiscono uno o piu' risultati, dipendenti dall'input.
L'uso di funzioni permette di individuare nel programma unita' logiche, che svolgono compiti ben definiti, e di costruire un programma complesso utilizzandole come fossero estensioni del linguaggio di programmazione.
Il linguaggio dei compilatori introduce altri costrutti logici, oltre quelli
propri della macchina, costrutti che sono poi ricondotti dal compilatore
stesso a quelli della macchina; il programmatore ha pero' a disposizione
strutture logiche di piu' alto livello, che gli facilitano il lavoro.
A volte nella CPU c'e' hardware apposito che facilita l'esecuzione
di questi costrutti.
Abbiamo quindi:
Con l'evoluzione dell'informatica i programmi diventano sempre piu'
grandi e complessi: oggi non sono rare componenti software che
contengono milioni di istruzioni. Affrontare problemi di
grandi dimensioni, sviluppati da team numerosi di programmatori,
diventa difficile. Per affrontare questi problemi nasce, a meta' degli
anno 80, la programmazione ad oggetti: il C viene esteso con nuove
istruzioni e nasce il C++ ; Java, linguaggio di programmazione
della Sun, inteso per applicazioni di rete, nasce gia' come
linguaggio ad oggetti. Anche la Microsoft produce compilatori
per la programmazione ad oggetti. Negli anni 90 la programmazione
ad oggetti diventa di moda ed e' oggi applicata anche a problemi che
non ne avrebbero bisogno.
La programmazione ad oggetti e' un argomento complesso,
non si puo' pretendere di capirla veramente se non si sono affrontati
in pratica certi problemi di programmazione.
Nella programmazione ad oggetti si fa uso esteso di strutture, che vengono a contenere anche le funzioni che operano sulle strutture stesse; queste strutture, dette "oggetti" vengono usate senza sapere nulla della loro struttura interna; i dati interni sono invisibili dall'esterno e l'oggetto si usa chiamando le sue funzioni (dette metodi) che ne costituiscono l'interfaccia. Questo isolare e nascondere le proprieta' e variabili di un oggetto si chiama "incapsulamento".
L'oggetto e' quindi un insieme di dati "chiuso" che si utilizza dandogli dei "comandi", ha un suo stato interno, ben definito cui pero' si accede solo con la sua interfaccia.
Nella programmazione ad oggetti il programmatore procede in diverse fasi:
Oggetti possono essere creati estendendo le proprieta' di altri oggetti, questo si chiama "ereditarieta'". L'Ereditarieta' semplifica molto la costruzione di oggetti complessi.
E' possibile creare oggetti e funzioni in modo indipendente dal tipo di dati che trattano, il tipo viene specificato solo quando l'oggetto viene istanziato ed il compilatore crea un oggetto relativo al tipo di dato corretto. Questi oggetti, in cui i tipi sono specificati solo quando l'oggetto viene creato sono detti "templates".
Inoltre e' possibile scrivere parti del programma in modo indipendente dagli oggetti che si trattano, utilizzando solo le specifiche delle interfacce in generale (collegamento dinamico o "late binding").
E' difficile capire i vantaggi della programmazione ad oggetti se non si sono mai affrontati grossi progetti, ad ogni modo da quanto detto dovrebbe apparire evidente come la programmazione ad oggetti renda facile il separare un programma in parti indipendenti, che possano essere sviluppate da gruppi diversi e faciliti la riutilizzabilita' di parti di programmi. Molto lavoro viene demandato al compilatore e la progettazione del software puo' focalizzarsi sul disegno delle interfacce, senza doversi occupare del dettaglio degli algoritmi se non in una seconda fase.