Programmare i computers

Gli antenati dei moderni computers erano macchine progettate e costruite per svolgere ciascuna un unico compito: una macchina per risolvere una specifica equazione, una per generare una certa serie di numeri e via dicendo; sono famose le macchine che il matematico americano Derrick Norman Lehmer costruì negli inizi del '900 (assieme a suo figlio Derrik Henry), utilizzando pignoni e catene di bicicletta [cfr. Marcus Du Sautoy, "L'enigma dei numeri primi"; pag. 360].

Fu in una fabbrica di stoffe che venne in mente di dare delle istruzioni ad una stessa macchina attraverso schede perforate per farle svolgere più compiti; in questo caso, a seconda della scheda inserita, la macchina tesseva un motivo diverso; era possibile svolgere più compiti con la stessa macchina: quello in un certo senso fu il primo programma per computer della storia.

Una serie di istruzioni

Un programma è quindi una serie di istruzioni eseguibili da un computer, che descrivono una procedura (il più delle volte un algoritmo matematico).

Facciamo un esempio pratico: più o meno tutti abbiamo un'idea di come si prepari una pentola di spaghetti. Il procedimento è semplice: fare bollire un po' di acqua salata, calare gli spaghetti, e infine scolarli quando sono cotti.

Per costruire il "programma degli spaghetti" sarà necessario, anzitutto, scomporre il procedimento intuitivo in passi semplici, che descrivano con precisione tutto il procedimento, dall'inizio alla conclusione:

  1. Riempire di acqua una pentola
  2. Aggiungere il sale
  3. Mettere la pentola sul fuoco
  4. Aspettare
  5. L'acqua bolle?
    • : passare al punto successivo
    • no: tornare al punto 4
  6. Calare la pasta nell'acqua
  7. Aspettare 12 minuti (il tempo di cottura degli spaghetti)
  8. Assaggiare la pasta: è cotta?
    • : passare al punto successivo
    • no: aspettare 1 minuto e tornare al punto 8
  9. Scolare la pasta

Questi otto passi costituiscono un algoritmo, ovvero una sequenza finita di operazioni semplici che descrivono la soluzione di un problema.

Scrivere un programma significa tradurre un algoritmo in un linguaggio che sia comprensibile dal computer. Di questo parleremo meglio tra poco; per ora si può solo osservare che l'"algoritmo degli spaghetti" scritto qua sopra non può essere tradotto in un programma per computer perchè, ovviamente, i normali calcolatori non sono in grado di maneggiare pentole, fornelli e spaghetti...

Questa banale osservazione è in realtà utile per farsi un'idea di cosa è possibile fare con un linguaggio di programmazione: certamente non fare la pasta, ma comandare tutte le funzioni del computer (ad esempio, fare dei calcoli col processore, scrivere e disegnare sullo schermo, o creare, aprire e salvare files, il tutto in maniera automatica). Se per una persona l'algoritmo degli spaghetti è intuitivo, tipicamente i primi esempi di programma per computer sono cose del tipo "Calcolare l'area di un rettangolo", o "Fare la somma dei primi dieci numeri", piuttosto che "Scrivere al contrario il nome dell'utente". Il resto è fantasia: tutto quello che vedi sul tuo monitor è stato certamente disegnato da un programma per computer.

Altra cosa interessante è l'evidente semplicità delle istruzioni. Il calcolatore è stupido, ovvero non è in grado di eseguire operazioni che richiedono un ragionamento; quest'ultimo infatti deve essere fatto dal programmatore, quando, prima di creare il programma scompone questo ragionamento nella sequenza di operazioni più semplici, che, come abbiamo visto, è detta algoritmo.

Programmare programmi, che programmano programmi?

I più curiosi avranno già notato che, senza un programma da eseguire, un computer è come un'automobile senza autista: non può fare nulla. In qualsiasi momento, da quando si preme il tasto di accensione allo spegnimento, ci dev'essere almeno un programma che dica alla macchina cosa fare.

Il primo programma che ogni computer trova quando si accende, prima ancora del sistema operativo, è il BIOS (Basic Input/Output System), e non si trova sul disco rigido, ma su una piccola memoria attaccata alla scheda madre (quella grande alla quale sono attaccate tutte le altre, per intenderci); il BIOS è il responsabile di tutte le scritte che compaiono all'avvio del PC, e svolge i primissimi compiti durante l'accensione; Inoltre è sempre il bios che gestisce lettura e scrittura su memoria e dischi e tutte le altre funzioni base della macchina.

Ma per rendere accessibili queste basilari istruzioni ai comuni utenti è necessario che un altro programma si ponga in mezzo come un interprete tra umano e macchina in modo più o meno trasparente: il sistema operativo.

Ciò che programmeremo noi non è il bios e non è esattamente il SO. Detto in modo un po' grossolano, noi scriveremo delle istruzioni in un linguaggio abbastanza simile al nostro che verranno trasformate in istruzioni comprensibili dal sistema operativo che le tradurrà in impulsi e chiamate al bios che alla fine di questa catena invierà corrente ai circuiti giusti producendo il risultato che desideriamo.

Un linguaggio abbastanza simile al nostro

Ho parlato di un linguaggio abbastanza simile al nostro. Un linguaggio di programmazione è un insieme di comandi da impartire alla macchina che vanno scritti secondo una sintassi molto rigida e precisa; il computer, infatti, non essendo intelligente, può elaborare soltanto comandi schematici e "robotici". Questi comandi sono in genere parole inglesi e la sintassi è costituita da una varietà di parentesi, virgolette e punteggiatura varia; ad esempio per dire di scrivere sullo schermo la parola "ciao" noi pensiamo:

scrivere sullo schermo la parola "ciao".

Ma alla macchina diremo:

write('Ciao');

oppure

printf("Ciao");

a seconda del linguaggio, perchè esistono diversi linguaggi. O ancora per dire

se 2 + 2 fa 4 allora scrivi sullo schermo la parola Giusto, altrimenti la parola Sbagliato.

dovremo scrivere:

if(2+2=4) then write('Giusto') else write('Sbagliato');

in Pascal, oppure:

if(2+2==4) { printf("Giusto"); } else { printf("Sbagliato"); }

in linguaggio C.

Più di un linguaggio

A questo punto possiamo cominciare a fare distinzioni tra i vari linguaggi esistenti; scopriremo che ne esistono parecchi, ognuno con i suoi pregi ed i suoi difetti: uno produrrà programmi più veloci, uno permetterà di gestire grandi progetti, un altro sarà più facile da imparare, e via dicendo...

livello alto e livello basso

Cominciamo col dire che i linguaggi di programmazione sono divisi in due grosse categorie: i linguaggi di livello basso e quelli di livello alto. Contrariamente a quello che si potrebbe pensare, queste categorie non servono a dividere i linguaggi belli da quelli brutti, ma dividono i linguaggi "macchinosi", da quelli un po' più "umani": un linguaggio di basso livello, ad esempio l'Assembly, è fatto per "parlare" direttamente col il processore. Questo significa principalmente due cose:

  • I limiti dei linguaggi low-level coincidono con i limiti della macchina: con un linguaggio a basso livello si può fare tutto, comandando ogni parte del computer fino ai dettagli più piccoli (per questo il linguaggio Assembly è il prediletto dai programmatori di virus). Inoltre questi linguaggi sono estremamente veloci e compatti: con essi è possibile far stare un sistema operativo completo in poco più di 1MB di spazio (http://www.menuetos.net/)!
  • Per eseguire un'operazione qualsiasi, anche le più semplici, è necessario scendere nei dettagli più piccoli della macchina: il codice Assembly è lungo e difficile da scrivere e leggere; inoltre per programmare a basso livello, come è facile immaginare, è indispensabile conoscere perfettamente il funzionamento della macchina.

Il codice seguente è Assembly, e, a dispetto delle sue sembianze incomprensibili, serve semplicemente a scrivere sullo schermo la frase "Hello, world":

IDEAL
MODEL SMALL
STACK 100h
DATASEG
    HW      DB      "hello, world", 13, 10, '$'
CODESEG
Begin:
    MOV AX, @data
    MOV DS, AX
    MOV DX, OFFSET HW
    MOV AH, 09H
    INT 21H
    MOV AX, 4C00H
    INT 21H
END Begin

Vice versa in un linguaggio di livello alto tutte le istruzioni hanno nomi "umani" (tipicamente sono parole della lingua inglese), che rendono la programmazione più semplice e, quanto possibile, amichevole.

I linguaggi di livello alto si capiscono molto più al volo dell'Assembly, e sono i più studiati da chi comincia (spesso però con qualche compromesso sulla velocità di esecuzione); fanno parte di questa categoria i vari Basic, il Pascal, il Python, Java e altri meno noti.

Questo è un esempio di "Hello, world" in Java:

public class HelloWorld
{
    public static void main(String[] args)
    {
        System.out.println("Hello World");
    }
}

È necessario alla fine parlare del linguaggio C. Il C è uno dei linguaggi più usati e diffusi nel mondo della programmazione, ed è solitamente classificato come linguaggio di medio livello, poichè permette di scendere nel dettaglio della macchina, senza rinunciare ad una sintassi (per quanto è possibile) facile da leggere.

La grande maggioranza delle applicazioni è scritta in C; probabilmente anche il sistema operativo che stai usando è scritto in C.

linguaggi compilati e linguaggi interpretati

Prima di concludere il discorso manca ancora un tassello: il passaggio da codice sorgente a programma eseguibile.

Prendiamo ad esempio il codice di "Hello world" in Java scritto qua sopra. Il lettore potrebbe credere che un computer sia in grado di capirlo ed eseguirlo: sbagliato! Il computer può eseguire solo codice a basso livello, ed in particolare in linguaggio macchina (sì, quello fatto da soli 0 e 1). Il codice qua sopra è scritto in un linguaggio ad alto livello (Java, appunto), ed è detto codice sorgente del programma Hello, world.

Prima di essere eseguito, il codice sorgente deve essere tradotto in linguaggio a basso livello, ovvero nelle istruzioni vere e proprie da inviare alla CPU. Fortunatamente questa traduzione è automatica, e può avvenire in diversi modi, a seconda del tipo di linguaggio:

  • Linguaggi compilati - La maggioranza dei linguaggi adottano il sistema della compilazione: il codice sorgente viene tradotto in linguaggio macchina da un apposito programma detto compilatore, il quale, dai sorgenti, produce il file eseguibile (in Windows, per intenderci, un files .exe), che contiene soltanto linguaggio macchina.

    Il compilatore libero più usato in ambiente Linux è il GCC (Gnu Compiler Collection), ma esistono molti altri compilatori "storici", prodotti dalle più grandi aziende dell'informatica, come ad esempio Intel, Borland o Microsoft.

  • Linguaggi interpretati - Alcuni linguaggi sono fatti per essere tradotti "al volo", direttamente durante l'esecuzione. Per fare questo è necessario che un programma, detto interprete, legga il codice del programma, e, simultaneamente, lo traduca in istruzioni a basso livello.

    Questo approccio, come si può intuire, penalizza la velocità di esecuzione, ma a volte rende più comoda la creazione dei programmi più semplici. Un esempio di linguaggio interpretato è Python, di cui esiste anche un interprete on-line: http://try-python.mired.org/.

Ci sono poi parecchi linguaggi particolari, come Java, a metà tra i compilati e gli interpretati, ed i linguaggi per il web (PHP, ASP ecc..), che sono eseguiti "a distanza", ma di questi se ne parlerà nelle apposite sezioni.

Quale linguaggio usare

Si giunge così alla fatidica domanda: qual'è il linguaggio più bello di tutti? Naturalmente non è possibile rispondere a questa domanda, perchè ogni linguaggio è adatto ad un particolare scopo. Certo per iniziare a programmare nel XXI secolo difficilmente si sceglieranno Assembly e simili, ma piuttosto un linguaggio un po' più "umano".

Per sperimentare senza troppo impegno cosa significa programmare può essere divertente buttare giù qualche riga di Python, sapendo però che, prima o poi, per tutti i programmatori arriva il momento di imparare C e/o C++ (la differenza sarà spiegata nelle apposite sezioni), sapendo che non appariranno magicamente icone o finestre con menù, pulsanti e quant'altro (per fare questo in C serve un bel po' di esperienza), ma che si dovrà lavorare sul terminale, leggere le scritte bianche su sfondo nero, inserire numeri, parole e sbattere un po' la testa sui propri errori, per capire fino in fondo la programmazione.

Altre informazioni sui vari linguaggi di programmazione si possono trovare in Linguaggi di programmazione.


Non mi resta che fare gli auguri a chi si volesse lanciare nella programmazione e invitarvi a riempire le pagine dei commenti con qualsiasi dubbio o richiesta di chiarimento possa sorgere.