Capitolo 1 - MACCHINE, SISTEMI, LINGUAGGI

 

 

 

            1.1 - La rivoluzione informatica.

 

                Il sostantivo computer deriva dal verbo inglese to compute, che enfatiz­za l'aspetto operativo del calcolo; esso può essere reso in italiano con calcolatore, o elaboratore, termini meno specializzati, ma l'originale è ormai entrato nell'uso corrente e non necessita di traduzione.

 

                Le prime macchine a tecnologia elettronica sono state costruite tra il 1940 ed il 1950  con lo scopo di eseguire  calcoli, ricerche matematiche ed applicazioni scientifiche con velocità e precisione di gran lunga superiori rispetto ai dispositivi meccanici, gli unici costruiti fino a quel tempo.

 

                Non è un caso, naturalmente, che tali macchine siano state realizzate nel periodo del prevalere di interessi militari per il contesto bellico, lo stesso che ha visto la nascita delle applicazioni dell'elettronica, dell'ener­gia nucleare, delle tecniche di ricerca operativa, per citarne solo alcune.

 

                Per quanto grande potesse essere l'interesse per la realizzazione di apparecchiature per la ricerca scientifica e per applicazioni militari,  la spinta più consistente per lo sviluppo è però venuta da altri campi, soprattutto dalla gestione aziendale.

 

                L'attività di calcolo riguarda dati numerici, ma essa è solo un aspetto di una più generale elaborazione dei dati, spesso non numerici: ad esempio, liste di nomi, indirizzi, e così via.

 

                Elaborare dati significa eseguire operazioni, talvolta aritmetiche (somme, prodotti, ecc.), talvolta non (ordinamenti, ricerche, ecc.), quasi sempre organizzate in sequenze di natura automatica e ripetitiva, la cui esecuzione può quindi essere vantaggio­samente delegata ad una macchina; la generalizzazione dei tipi di dati trattabili - dai soli numeri ad oggetti, quali arbitrarie sequenze di caratteri - interessa un ambito applicativo  che dalla ricerca scientifica si estende ad una grande gamma di attività umane: commerciali, organizzative, gestionali.

 

                Accanto all'utenza  scientifica è così comparsa  quella commerciale, che negli anni '50 ha dato allo sviluppo delle macchine un impulso motivato da grandi interessi economici, tali da rendere disponibili risorse altrimenti difficilmente reperibili per la sola ricerca astratta.

 

                La rapidissima evoluzione delle tecnologie costruttive - hardware - e delle tecniche, o metodi logici di gestione - software - è stata scandita sull'arco di pochi decenni dal succedersi di diverse generazioni di apparec­chiature sempre più compatte, veloci ed economiche, la cui diffusione capilla­re interessa la quasi totalità delle attività umane.

 

                I problemi posti dall'architettura fisica e logica della macchina hanno originato una nuova disciplina scientifica, la computer science, o scienza dell'informazione, o informatica, ormai affermatasi come disciplina autonoma sullo stesso piano, ad esempio, della fisica o della chimica.

 

                E' certamente giustificato parlare di una rivoluzione informatica in analogia a quella industriale, che a partire dal XVIII secolo ha radicalmente trasformato il rapporto dell'uomo con la società e l'ambiente in cui vive;  già in pochi decenni l'informatica ha apportato cambiamenti altrettanto pro­fondi, ed altri ben maggiori se ne attendono.

 

                Buona parte dello sviluppo si è verificato non per caso negli USA, cioè nella nazione maggiormente industrializzata, cosa che ne ha condizionato molti aspetti; in particolare la terminologia, con l'introduzione di neologismi (computer, software) o nuovi sensi per vecchi vocaboli che spesso rendono la traduzione ardua, se non impossibile.

 


 

 

            1.2 - La macchina ed il suo utente.

 

                Fino all'inizio degli anni '80 l'effettivo contatto con la macchina era riservato a pochi specialisti, teorici della materia, ingegneri e tecnici elettronici, esperti dei linguaggi artificiali di programmazione.

 

                Il decennio è stato marcato dalla comparsa dei Personal Computer; ini­zialmente poco più che giocattoli, essi hanno rapidamente raggiunto capacità equivalenti o superiori rispetto ai sistemi medio-grandi del decennio prece­dente, con costi collocati tra quelli degli elettrodomestici e delle automobi­li, tali cioè da farne oggetti di largo consumo.

 

                La medesima evoluzione tecnologica ha influito anche sui grandi sistemi, aumentandone capacità e flessibilità e riducendone i costi, in modo tale che è ormai difficile trovare scrivanie d'ufficio o banchi d'officina sprovvisti di video e tastiera.

 

                La larga diffusione ha posto la necessità, prima poco considerata, di rendere l'accesso alla macchina abbastanza semplice da non costituire più un grave ostacolo per una utenza improvvisamente esplosa, che in genere  non può o non vuole curarsi dei dettagli tecnici dell'interazione uomo-macchina, ma è solo interessata all'utilizzazione di programmi specifici.

 

                L'attenzione si sposta quindi sui  sistemi operativi, o insieme di servizi per la gestione di base, che da un lato interessa lo specialista della progettazione, ma dall'altro costituisce la interfaccia tra le operazioni effettive di macchina ed il modo in cui l'utente le percepisce.

 

                Si pensi ad una attività di una certa complessità quale può essere quella di una tipografia. Il mercato offre programmi pronti per Personal Computer di fascia alta che permettono di eseguire e controllare  tutte le operazioni: acquisizione di testi da dischetti o per telefono, genera­zione della forma delle pagine e dei caratteri, disposizioni grafiche con o senza colori, ecc.

 

                La flessibilità dei servizi offerti è tale da permettere ad un solo operatore di controllare tutte le azioni necessarie per ottenere, ad esempio, la stampa di un quotidiano a partire da testi e fotografie ricevute per telefono, non escludendo neppure il controllo delle rotative e delle spedizioni.

 

                L'utente di servizi di questo tipo deve conoscere bene i propri proble­mi,  ma non si deve supporre che egli sia pure un esperto di sistemi e lin­guaggi di programmazione. Sia il package, o servizio applicativo, sia il sistema operativo gli dovranno quindi essere proposti in una forma che non richieda competenza particolare in campo informatico, semplifichi al massimo le sue opera­zioni ed  gli dia la più dettagliata assistenza  possibile in caso di necessi­tà (opzioni di help, o aiuto).

 

                La richiesta di 'pacchetti' di questo tipo è abbastanza grande da giu­stificare gli sforzi di un gran numero di produttori in un mercato in cui la concorrenza è molto forte, e che é quindi grandemente stimolato all'innovazione.

 

                L'utente è ormai nella maggior parte dei casi caratterizzato in questo modo: utilizza uno o più programmi in un certo contesto di integrazione ed è poco o per nulla propenso ad interessarsi dei dettagli operativi; sempre più spesso si verifica la stessa situazione anche per servizi qualificati in senso scientifico.

 

                Vi sono però casi in cui, per interesse o necessità, di deve scendere più a fondo, ad esempio per costruirsi strumenti non reperibili in una forma standard; il contatto con i dettagli del sistema operativo e/o l'impiego di un linguaggio di programmazione non possono allora essere più evitati.

 


 

 

            1.3 - La base: i linguaggi degli ASSEMBLER.

 

                In pochi decenni di cronaca/storia  vi è stata una enorme proliferazione di linguaggi di programmazione; con questi termini si indicano gli insiemi di regole che definiscono le convenzioni necessarie per comunicare alla macchina sequenze di istruzioni finalizzate all'ottenimento di uno scopo; i linguaggi vengono suddivisi in diversi livelli, a seconda del grado di astrazione rispetto alla costituzione reale della macchina e degli scopi per cui sono codificati.

 

                Poiché ogni macchina viene progettata per eseguire un certo numero di operazioni elementari, da scegliere in una vasta gamma di possibilità, il costruttore deve prevedere una forma di linguaggio detto di basso livello, con cui richiedere dettagliatamente la loro esecuzione.

 

                Le relative convenzioni formano il cosiddetto linguaggio macchina,  che è un insieme di codici strettamente dipendente dalla architettura fisica e varia per costruttore e modello: esso prevede codici per attivare le funzioni (operazioni) elementari della macchina, con il massimo grado di dettaglio possibile.

 

                Per essere utilizzabile, un linguaggio macchina è normalmente accompa­gnato da uno speciale programma detto ASSEMBLER, il quale collega sequenze di comandi elementari in unità logiche complesse; è divenuto abituale utiliz­zare il termine per indicare lo stesso linguaggio macchina, cosa che faremo anche in questo contesto.

 

                L'impiego di un ASSEMBLER è naturalmente inevitabile per costruire i primi servizi di base, ma in questa fase esso riguarda gli specialisti che progettano la macchina ed il software che la correda; per l'utente intermedio o finale, esso è in genere solo l'estrema risorsa per la soluzione di problemi speciali, tali da non ammettere altra ragionevole altrnativa.

 

                Programmare in ASSEMBLER significa infatti investire risorse per l'im­piego su un solo tipo di macchina; se si vuole utilizzare lo stesso programma su un'altra è in genere necessaria una riscrittura completa, che raramente è una semplice trasposizione.

 

                Le 'frasi' tipiche di un ASSEMBLER si riferiscono alle operazioni più elementari possibile; ad esempio:

 

  (1.3.1)   COPIA un dato dalla posizione A alla posizione B ;

                SOMMA il dato in N con il dato in M con risultato in N ;

                CONFRONTA il dato in Y con il dato in Z ;

                SALTA all'istruzione scritta 100 righe più avanti.

 

e l'attenzione sui singoli dettagli operativi tende a generare una situazione descrivibile nei termini alberi / foresta: i primi fanno perdere di vista la seconda, che in questo caso è la logica generale del problema da risolvere.

 

                Si deve però dire che la maggior parte dei linguaggi ASSEMBLER sono oggi formulati come MACRO-ASSEMBLER, cioè dotati di un insieme di definizioni di sequenze operative (MACRO) già predisposte, che evitano almeno in parte al programmatore il problema delle ripetizioni dell'estremo dettaglio.

 

 

 

 

            1.4 - I linguaggi di alto livello.

 

                Un ASSEMBLER, linguaggio di basso livello, nasce con e per una macchina specifica; un cambio di costruttore o anche la evoluzione nel tempo dello stesso rende inutilizzabili i programmi, dei quali risultano quindi fortemente ridotti l'ambito applicativo ed il ciclo di vita.

 

                Un limite ancora più importante riguarda l'efficienza dello strumento in funzione del problema da affrontare; come già accenna­to sopra, la necessità di attenzione continua ai minimi dettagli operativi può facilmente confondere la struttura logica nel suo insieme.


 

                E' quindi opportuno definire linguaggi di alto livello, i quali:

 

   descrivano dati ed operazioni in termini esclusivamente logici, non riferiti ad alcuna particolare architettura fisica di macchina;

 

   permettano forme espressive sintetiche, adeguate alla descrizione della struttura dei problemi e non vincolate  dalle necessità operative della macchina.

 

                 Un esempio molto semplice, che verrà ripreso nel seguito, è dato dalla somma di due numeri; indicando con A, B i termini e con C il risultato, per un ASSEMBLER è necessario specificare i dettagli:

 

  (1.4.1)   preleva il primo addendo dalla posizione A ;

                preleva il secondo addendo dalla posizione B ;

                esegui la somma collocandola in A ;

                poni il risultato nella posizione C ;

 

la descrizione reale varia con la macchina; un linguaggio di alto livello deve invece permettere di esprimersi in modo sintetico; ad esempio come in:

 

  (1.4.2)   assegna a C il valore di A + B ,

 

o meglio ancora:

 

 (1.4.3)    C = A + B .

 

                Si richiede cioè che le descrizioni siano il più possibile astratte e vicine ai linguaggi naturali, eventualmente specializzate per scopi particola­ri quali quelli matematici; vale a dire, mentre i linguaggi di basso livello sono costruiti a misura di macchina, quelli di alto livello debbono esserlo a misura d'uomo.

 

                Le sequenze operative come la (1.4.2) o la (1.4.3), contrariamente a quelle del tipo (1.4.1), non sono direttamente utilizzabili da parte della macchina, poiché esse non descrivono più singole azioni elementari.

 

                La conversione della (1.4.2), o della (1.4.3) nella (1.4.1) è però automatica ed è quindi possibile delegarla alla macchina stessa come fase preliminare alla esecuzione della azione effettiva.

 

                Un linguaggio di alto livello richiede strumenti di traduzione, che a seconda di certe caratteristiche operative si diranno interpreti, oppure compilatori, il cui scopo è la generazione automatica di sequenze operative reali a partire da descrizioni più sintetiche.

 

                Il sistema operativo, o gestione di base delle risorse della macchina può essere considerato, per come lo percepisce un utente, un linguaggio di programmazione posto al più alto livello possibile. Esso è in genere utilizza­to in forma di dialogo interattivo, con comandi interpretati ed immediatamente eseguiti.

 

                A questo punto di vista sono assimilabili anche i sistemi applicativi predisposti per l'uso da parte dell'utente finale, che spingono la logica della aggregazione e della sintesi fino a considerare interi programmi come singole operazioni, esattamente come accade per il sistema operativo.

 

                Il linguaggio di programmazione di basso o alto livello, quello dei comandi di un sistema operativo e  quello delle opzioni di menù in un package applicativo per utente finale pongono quindi tutti problemi di apprendimento simili, anche se su piani concettualmente molto diversi; tutti richiedono il medesimo grado di rigore logico nelle definizione delle operazioni possibili e della natura dei dati interessati dalle operazioni.

 


 

 

            1.5 - Le caratteristiche di un linguaggio.

 

                Ogni linguaggio di programmazione ha per obiettivo la descrizione della sequenza di azioni richieste alla macchina in funzione del raggiungimento di un risultato definito; come si è detto, ciò è vero anche per contesti quali i sistemi operativi e quelli applicativi.

 

                Perché l'azione possa avvenire è necessario che ogni richiesta venga formulata in modo esplicito e non ambiguo; lo stesso grado di precisione é pure necessario per la definizione dei dati che sono gli oggetti di ogni singola operazione.

 

                I dati elementari riconoscibili ed 'operabili' da parte della macchina non sono molti: singoli caratteri, numeri interi, numeri non interi con diver­si possibili livelli di precisione. Possono esistere estensioni quali i valori logici (vero/falso) ed i numeri complessi, ma i primi tre tipi (o categorie) sono i più comuni. Un caso più complesso è dato dalle stringhe, o sequenze di caratteri di lunghezza arbitraria, che per qualche aspetto possono essere considerate dati elementari, ma per altri debbono viste come strutture più complesse costruite a partire da dati elementari.

 

                I dati vengono normalmente indicati tramite nomi simbolici, che denotano entità variabili; l'appartenenza di ognuna di esse ad un tipo ben preciso è essenziale per determinare:

 

  (1.5.1)   l'insieme di valori ammissibili ;

                le operazioni lecite su un tipo di oggetti.

 

                Non è per esempio sensato, in generale, trattare i caratteri come dati per una operazione aritmetica; inoltre, l'insieme dei caratteri possibili è certamente limitato.

 

                 Una prima classe di operazioni è data dalla assegnazione del valore ad una variabile; il valore é in genere il risultato della valutazione di una espressione più o meno complessa.

 

                 Una seconda classe riguarda invece lo scambio di dati tra un dispositivo esterno e la unità centrale della macchina, termini che verranno definiti meglio nel seguito e sono per il momento da intendere in senso intuitivo; queste sono dette  operazioni I/O, da Input/Output, che sono i termini di uso corrente per tutte le operazioni di immissione o emissione di dati.

 

                Per quanto possa sembrare strano, non vi sono altre classi di operazioni sui dati oltre alle due appena indicate, a meno di volere includere in una categoria separata la valutazione di risultati temporanei (intermedi in un calcolo) ai quali non corrispondono nomi simbolici.

 

                Esiste invece l'esigenza di azioni di controllo, di cui le più semplici sono l'indicazione esplicita del punto di avvio e delle condizioni di arresto delle operazioni.

 

                Le categorie più importanti sono però quelle che si occupano della organizzazione del flusso operativo, che solo in casi estremamente semplici si riduce ad una sequenza lineare come la (1.4.1) e generalizzabile in:

 

  (1.5.2)   inizia ;

                esegui azione_1 ;

                ...............

                esegui azione_n ;

                arrestati .

 

                Si osservi la forma, simile a quella già adottata nelle (1.4.1) ed (1.4.2), con le azioni descritte con verbi imperativi: FAI questo, cioè con la struttura OPERAZIONE - eventuali operandi; questa è appunto la forma general­mente adottata nelle 'frasi' dei linguaggi di programmazione.

 

                I problemi aventi un minimo di complessità richiedono però organizzazio­ni più evolute, che rientrano in due categorie, il controllo delle alternative e quello delle ripetizioni (iterazioni, cicli), descrivibili con schemi come:


 

  (1.5.3)   SE vale questa condizione ALLORA esegui azione_1 ;

                ALTRIMENTI esegui azione_2 ;

 

  (1.5.4)   PER un certo numero di volte:

                RIPETI la tale azione .

 

                Le condizioni che controllano le alternative dipendono in genere dal valore dei dati durante l'esecuzione del programma; i 'cammini' di istruzioni eseguite sono così effettivi flussi dinamici.

 

                Delle (1.5.3) ed (1.5.4)  esistono parecchie varianti importanti: nella (1.5.3) la clausola ALTRIMENTI potrebbe non esserci, o le alternative potreb­bero presentarsi in una cascata multipla  SE .. ALTRIMENTI SE ..  ALTRIMENTI .. ; le ripetizioni, invece, potrebbero essere determinate da condizioni diverse da un conto esplicito, come in:

 

  (1.5.5)   RIPETI la tale azione

                FINCHE' vale la tale condizione ,

 

e così via; in questo momento non interessa però la classificazione formale delle strutture logiche possibili.

 

                Ciò che importa mettere in evidenza è invece lo 'scheletro logico' necessario ad ogni linguaggio, che comprende:

 

  (1.5.6)   - classificazione e definizione dei dati;

                - condizioni di avviamento ed arresto;

                - istruzioni per l'assegnazione;

                - istruzioni di I/O;

                - controllo delle alternative;

                - controllo dei cicli ripetitivi;

                - convenzioni per la suddivisione in moduli funzionali.

 

                La struttura di base di un linguaggio è completamente descritta dalla (1.5.6), che però è abbastanza generale da non suggerire nulla sulle conven­zioni che ogni particolare linguaggio adotta per la effettiva realizzazione dello schema, o sua implementazione.

 

                Diamo nel seguito un breve riepilogo dei principali linguaggi di alto livello, allo scopo di descriverne l'evoluzione; ne menzioneremo solo alcuni tra le centinaia o migliaia di proposte diverse che sono state formulate, con un criterio che dovrebbe essere quello della massima probabilità di riferimen­to ad un contesto familiare o necessario.

 

                Per completare queste considerazioni, si deve dire esplicitamente che i linguaggi di cui ci occupiamo, la cui struttura ricalca cioè le linee traccia­te in precedenza, sono del tipo detto predicativo, con ovvio riferimento alle strutture linguistiche di cui si sono visti esempi.

 

                Vi sono pure linguaggi costruiti su basi diverse, non predicative, ed in genere orientati alla soluzione di problemi particolari: ad esempio il LISP, progettato per la trattazione di stringhe di natura generale, il PROLOG, che si inte­ressa al calcolo logico più che a quello aritmetico, una serie di altri pro­gettati per la gestione di banche-dati in cui prevalgono le strutture di relazione, MATHEMATICA o MAPLE, che sono oramai divenuti strumenti di uso generale per la ricerca e le applicazioni matematiche.

 

                Molti 'linguaggi' di questa categoria non sono stati inizialmente pro­gettati come tali, ma principalmente come sistemi applicativi dedicati a particolari problemi; con il tempo (e sotto la pressione di sistemi concorren­ti) essi sono stati dotati di molte strutture tipiche dei 'veri' linguaggi di programmazione.

 


 

 

            1.6 - Cenno alle strutture dei dati.

 

                Per concludere la descrizione generale dei linguaggi di programmazione è opportuno riprendere l'argomento dei dati, di cui all'inizio del precedente 1.5 si è detto che i fondamentali sono i caratteri ed i numeri di diverse specie; si è anzi precisato che essi sono dati elementari, o primitivi, che tutte le macchine e tutti i linguaggi debbono essere in grado di trattare in qualche modo.

 

                In genere, solo i problemi più semplici possono però essere affrontati in termini di soli dati elementari; assai più spesso è necessario fare ricorso a costruzioni o strutture più complesse.

 

                E' molto frequente il caso delle tabelle lineari, in cui una molteplici­tà di dati omogenei tra loro si distinguono per il posto occupato nella lista: primo, secondo, terzo, ecc. Tali insiemi vengono pure detti vettori, con terminologia di evidente origine matematica.

 

                La rappresentazione naturale delle componenti di un vettore è quella che utilizza la notazione degli indici per denotare il posto nella sequenza; è pure molto diffuso il caso di tabelle bilineari, o 'rettangolari', dette più comunemente matrici, che ordinano i propri elementi utilizzando una coppia di indici indipendenti.

 

                Molti problemi, non solo di interesse matematico, non potrebbero essere risolti, ma addirittura nemmeno formulati se non ricorrendo a tali organizza­zioni di dati. E' quindi evidente che un linguaggio di programmazione non può esimersi dal definire la trattazione degli insiemi strutturati di dati.

 

                Si è accennato in precedenza alle stringhe: queste sono appunto un esempio di organizzazione lineare costruita a partire da un dato più elementa­re, il carattere, anche se, come si è già detto, per certi aspetti esse po­trebbero essere considerate entità primitive più complesse.

 

                Il termine inglese ARRAY che può essere reso con insieme strutturato in una sequenza linearmente ordinata tramite uno o più indici, è quello con il quale diversi linguaggi indicano la struttura di cui parliamo.

 

                Essa è però ben lungi dall'essere l'unica possibile: ad esempio, una limitazione consistente per le applicazioni è data dalla omogeneità delle componenti (tutti caratteri, o tutti interi, o tutti numeri complessi, ecc.).

 

                Si pensi ad esempio ad una lista lineare di oggetti logici definiti come una terna di elementi: il primo è un numero intero, il secondo un numero non intero ed il terzo un stringa di caratteri; gli elementi della lista (che come tale ha la natura di un vettore) sono tra loro omogenei, ma essi non sono dati semplici, bensì una aggregazione arbitraria di dati semplici.

 

                Non approfondiamo ulteriormente il concetto, la cui definizione precisa è competenza dei vari linguaggi di programmazione, limitandoci a notare come la struttura delle operazioni sia solo una parte della definizione delle regole di un linguaggio. La specificazione dei generi, o tipi di dati ricono­scibili e trattabili è almeno altrettanto importante.

 


 

 

            1.7 - I primi linguaggi: FORTRAN e COBOL.

 

                Il linguaggio di alto livello storicamente sviluppato per primo è stato chiamato FORTRAN (FORmulae TRANslator); le intenzioni che hanno condotto alla sua codifica sono chiara­mente deducibili dal nome stesso: trasposizione di formule (matematiche) in un contesto che ne renda possibile l'esecuzione da parte della macchina, pensata quindi come dedicata al calcolo.

 

                Di poco successivo è il COBOL (COmmon Business Oriented Language), il cui interesse si rivolge alla definizione dei dati complessi richiesti in ambiti gestionali ed alle operazioni necessarie per controllarne archivi anche molto estesi. Esso è divenuto il linguaggio commerciale per eccellenza ed ancora oggi ha un predominio assoluto nei grandi sistemi per l'elaborazione di dati (macchine dette mainframe).

 

                Il livello di specializzazione iniziale di FORTRAN e COBOL era tale che, ad esempio, non era possibile nel secondo eseguire una operazione come la radice quadrata, pur essendo  i due solo modi convenzionali di descrivere richieste operative per la stessa macchina.

 

                Tali limiti sono però stati rimossi abbastanza rapidamente; i linguaggi di programmazione non sono infatti contesti chiusi, ma entità in evoluzione, capaci di integrare una base già esistente con regole nuove, suggerite dai cambiamenti delle macchine o dalle nuove concezioni di altri linguaggi.

 

                Per il FORTRAN l'evoluzione è stata formalizzata in tre tappe, indicate con i nomi FORTRAN II, FORTRAN IV e FORTRAN 77; dalla capacità di trattare con un insieme ridotto di operazioni i soli valori numerici, interi o fixed point e non interi  o floating point si è passati ad una gamma molto ampia di tipi numerici e non, con corrispondenti grandi scelte di descrizioni linguistiche.

 

                Al momento anche lo standard 77 è ampiamente superato dalle versioni che propongono i vari costruttori e richiederebbe una riformulazione; è stato annunciato, ma al momento non è ancora diffuso, un nuovo standard FORTRAN 90.

 

                Per il COBOL, invece, si sono avuti le due revisioni principali dette COBOL 66 e COBOL 81, caratterizzate esse pure da un lato dall’estensione delle defini­zioni di dati e delle operazioni possibili e dall’altro da arricchimenti nella struttura linguistica, ma soprattutto dalla definizione di una serie di nuclei adattabi­li a diversi livelli di esigenze dei dispositivi fisici, ad esempio per la trattazione di dati in forma interattiva su un terminale video.

 

                Il concetto fondamentale del dato come RECORD, o registrazione su un adeguato supporto di memoria, è stato presente fin dall'inizio. I dati sono visti come strutture gerarchiche a più livelli, in  modo da permettere ampia libertà di scelta nell'elaborazione dell'intero insieme, necessaria a certi scopi, ed in quella delle sue parti, necessaria per altri.

 

                La condizione di assoluta prevalenza del COBOL per la programmazione commerciale non sembra destinata a cambiare sostanzialmente, soprattutto a causa dell'inerzia accumulata da sistemi che hanno richiesto grandi investi­menti in anni-uomo (l'unità standard di misura del lavoro nel software) e di cui non è ipotizzabile la sostituzione, mentre esistono invece le condizioni per l'evoluzione del linguaggio.

 

                Il FORTRAN è stato per molto tempo il protagonista principale della programmazione tecnico-scientifica e continua ad essere preferito da molti per la particolare facilità dell'apprendimento iniziale. La disponibiltà di grandi librerie di programmi pronti per l’uso (più esattamente sottoprogrammi) in materia matematica e statistica, molto ben collaudate e stabilizzate é poi un elemento di ‘inerzia’ quasi tanto importante come per il caso del COBOL.

 

                Il 'bacino di utenza' del FORTRAN (e non solo di questo linguaggio) è però progressivamente conquistato dal linguaggio C, che concluderà la nostra breve panoramica.

 


 

 

            1.8 - Un secondo stadio: ALGOL e PL/1.

 

                Si dice spesso che quella della programmazione è un'arte, non una scien­za; ciò è probabilmente vero, ma è certo che nei suoi stadi iniziali era un'arte molto rudimentale, con pochi strumenti operativi e fondamenti teorici scarsi o nulli, come appunto accadeva per FORTRAN e COBOL.

 

                Un primo deciso miglioramento nelle tecniche dell'arte, o scienza che sia, si è avuto con lo sviluppo di due altri linguaggi assai diversi tra loro, ALGOL e PL/1, dei quali il primo rende evidente fin dal nome (ALGOrithmic Language) l'intenzione di rivolgersi più all'analisi logica degli algoritmi, o sequenze operative, che alla descrizione  delle singole operazioni per la macchina.

 

                Il termine algoritmo può essere inteso intuitivamente come ricetta o tabella di marcia per la soluzione di un problema: si pensi ad esempio alla descrizione di come si fa la somma di due numeri interi.

 

                Una definizione imprecisa ma sufficiente per gli scopi attuali è la seguente: diciamo algoritmo ogni procedimento operativo per il quale:

 

  (1.8.1)   - sono definite le condizioni di avviamento;

                - per ogni operazione è univocamente determinabile l'operazione successiva;

                - sono definite le condizioni di arresto, che deve avvenire in un numero finito di passi.

 

                I linguaggi orientati agli algoritmi introducono i primi concetti strutturali, che evolvono le espressioni linguistiche in frasi, che non cercano più di riprodurre le effettive modalità operative, ma debbono invece permettere di esprimere con chiarezza i legami logici del genere di quelli evidenziati con le (1.5.3) ed (1.5.4).

 

                Da alcune caratteristiche tecniche si direbbe quasi che gli estensori dell'ALGOL non avessero molto interesse per l'utilizzazione effettiva del linguaggio sulla macchina: essendo stati trascurati certi elementi essenziali per la pratica, come l'interscambio di dati con i dispositivi esterni, l'ALGOL non è mai giunto a livelli significativi di impiego, ma è stato deter­minante per le successive definizioni formali dei linguaggi. E' inoltre stato lo strumento privilegiato per l'informatica teorica.

 

                Intenzioni simili erano alla base del PL/1 (poco modestamente, Program­ming Language / ONE ), con cui l'analisi delle strutture logiche è stata condotta molto più a fondo, avendo tra gli scopi quello di recuperare ed unificare ciò che di valido esisteva in FORTRAN e COBOL.

 

                In più, esso veniva proposto come strumento per lo sviluppo dei program­mi che costituiscono il sistema operativo  e non solo di quelli applicativi, che l'utente è interessato a sviluppare da sé. Questo aspetto è particolarmen­te importante, perché permette di ridurre il ricorso all'ASSEMBLER e rende le componenti del sistema operativo potenzialmente trasportabili tra macchine di tipo diverso.

 

                E' cioè il primo passo per svincolare il progetto (software) del sistema operativo da quello (hardware) della macchina.

 

                La diffusione del PL/1 è probabilmente stata limitata solo dall'essere esso troppo fortemente 'targato' col nome del costruttore più importante, la IBM; per l'epoca in cui è stato formulato e per le sue caratteristiche avrebbe infatti avuto buone probabilità di divenire il linguaggio di programmazione per eccellenza.

 

                La revisione strutturale coinvolge naturalmente tutti gli elementi elencati in (1.5.6), ma in particolare il primo e l'ultimo, da un lato con l'estremo rigore nella definizione dei dati e dall'altro con la suddivisione di un programma in sottounità, o procedure.

 

                Ognuna di esse è delegata ad un compito specifico, visto come problema a sé stante, ma utilizzabile in un altro contesto come una singola operazione; viene posta una cura particolare alle comunicazioni tra le varie unità di programma, soprattutto per il reciproco scambio delle strutture di dati.


 

                 La strutturazione in sottoprogrammi era già presente in FORTRAN e COBOL, ma in questa fase la sua definizione è stata molto più rigorosa e completa, in termini che verranno meglio valutati nel seguito.

 

                Le proprietà strutturali erano quindi, almeno in parte, già presenti nei linguaggi precedenti, che pure sono detti normalmente 'non strutturati'. Ma la strutturazione non è una proprietà specifica di un linguaggio, bensì un modo di pensare durante l'analisi logica del problema che si sta trattando; i temi che essa chiama in causa possono trovare maggiore o minore realizzazione formale in un linguaggio specifico, ma il 'filo conduttore' non è, e non può essere, legato ad alcuno di essi.

 

 

 

 

 

            1.9 - Un esperimento fortunato: il BASIC.

 

                All'inizio degli anni '60 si era resa disponibile la distribuzione su larga scala dei servizi di una grande macchina con modalità time-sharing, o divisione di tempo, su reti di telescriventi, anche  in collegamento telefoni­co remoto.

 

                La novità più importante era la gestione interattiva del sistema opera­tivo: tra macchina ed utente si stabiliva un dialogo continuo, fatto di doman­de e risposte flessibili, in contrapposizione a precedenti modalità assai più rigide, dette batch, o 'a lotto chiuso'.

 

                Poiché i linguaggi di programmazione erano ancora abbastanza 'tecnici' da richiedere nozioni consistenti sulla macchina per essere utilizzati anche in  modo minimo, si è tentato l'esperimento di definirne uno che non ponesse all'utente prerequisiti tecnici. Il risultato di questa 'sfida didattica' è stato il linguaggio  BASIC - Beginner's All purpose Symbolic Instruction Code o linguaggio simbolico d'uso generale per principianti.

 

                Mentre il FORTRAN ed il COBOL richiedevano la scrittura dell'intero programma ed una successiva compilazione separata per ottenerne una versione eseguibile, il BASIC offriva invece l'esecuzione immediata di ogni richiesta operativa, con la capacità di modificare continuamente i valori dei dati, provare più alternative nello stesso momento in cui venivano scritte, ecc.

 

                La caratteristica di linguaggio interpretato (interattivo), che permette di eseguire ogni riga indipendentemente dal contesto dell'intero programma, riduceva quasi a zero il tempo dell'apprendistato, permettendo di fare espe­rienze significative già dalle prime prove, effettuabili senza preliminari.

 

                Il contrasto con il periodo piuttosto lungo di ambientamento minimo per un linguaggio compilato faceva quindi del BASIC una novità sostanziale.

 

                Il dialogo continuo apriva nuove possibilità anche per un tema destinato ad avere sempre più importanza: la messa a punto di metodi e tecniche per il riconoscimento degli errori logici di un programma, o tecniche di debug, da bug (pidocchio o simili), nome di fantasia utilizzato per indicarli.

 

                Un consistente svantaggio era invece costituito (ed in parte lo è anco­ra) dall'essere il BASIC in controtendenza e quasi l'esatto opposto rispetto alle esigenze di accurata definizione strutturale.  La sua impostazione tende infatti a favorire  quanto descritto in precedenza con l'immagine degli alberi e della foresta; a fermare cioè l'attenzione più sui singoli passi esecutivi, molto vicini alla operatività di macchina, piuttosto che sul contesto logico generale.

 

                Gli stessi estensori del BASIC si sono probabilmente stupiti del succes­so registrato con il time-sharing, inevitabile viste le facilitazioni che il nuovo linguaggio era in grado di dare all'utenza improvvisamente esplosa, assai più ampia ma mediamente altrettanto poco qualificata.

 

                L'aumentare delle richieste ha costretto ad ampliare immediatamente le basi minime su cui il BASIC era nato, compromettendone la semplicità; con l'evoluzione di altri linguaggi esso sarebbe probabilmente scomparso, ma ha potuto fruire di una circostanza fortunata, la nascita e diffusione dei Perso­nal Computer della prima generazione, avvenuta tra la fine degli anni '70 e l'inizio degli '80.


 

                Nelle prime configurazioni essi avevano infatti capacità molto limitate, tali da impedire quasi l'impiego dei linguaggi di programmazione largamente affermati, mentre si potevano invece utilizzare con relativa facilità  versio­ni del BASIC capaci di operare in condizioni minime, mantenendo tutti i van­taggi della impostazione intuitiva del dialogo con l'utente, per di più  integrando in un solo contesto linguaggio e sistema operativo.

 

                A differenza dei linguaggi maggiori non esisteva uno standard ufficial­mente riconosciuto per il BASIC; le varianti introdotte dai costruttori per ottenere da una base minima un ragionevole strumento di gestione della propria macchina hanno  portato rapidamente ad una diversificazione di dialetti com­pletamente incompatibili tra loro, sia nella sintassi, sia in diverse rappre­sentazioni dei dati.

 

                Tale situazione caotica ha costituito certamente un limite per la possi­bile espansione del BASIC, che è comunque stata abbastanza consistente; un secondo ostacolo è derivato dalla rapida crescita delle capacità operative dei Personal, con la possibilità di installazione di altri linguaggi.

 

                Il BASIC è stato comunque e continua spesso ad essere la 'nave scuola' per le prime nozioni di programmazione, anche se nelle versioni correnti ha perso molti dei vantaggi derivanti dalla immediatezza intuitiva per acquisire invece proprietà strutturali e superare le limitazioni nella organizzazione dei dati e nella stessa fase di scrittura dei programmi.

 

 

 

 

 

            1.10 - La terza fase: il Pascal.

 

                Il punto di transizione dall'impostazione 'artigianale' a quella 'scien­tifica' della programmazione può essere in buona misura identificato con la formulazione e la diffusione di un linguaggio, il Pascal, denominato non con un acronimo, ma in omaggio a Blaise Pascal.

 

                I concetti che ne sono alla base erano quasi tutti presenti con l'ALGOL ed il PL/1, ma con il Pascal essi hanno trovato una sistemazione più sintetica e completa, giunta per di più nel momento in cui la larga diffusione delle macchine evidenziava i problemi derivanti dalla mancanza di criteri uniformi ed affidabili per la scrittura dei programmi.

 

                Il Pascal rende completa la precedenza della struttura logica delle operazioni rispetto alla loro descrizione dettagliata; si prescinde cioè completamente dalle capacità reali della macchina per concentrarsi invece su procedure e funzioni astratte, che operano su strutture di dati esse pure svincolate dalle rappresentazioni fisiche effettive.

 

                Ad esempio, la somma di due numeri può essere identificata con una reale operazione di macchina, ma non è così per l'ordinamento di una lista di dati, che richiede sequenze complesse di operazioni più elementari.

 

                Nell'analisi strutturale somma due numeri ed ordina una lista possono però entrambe venire viste come operazioni elementari di una  macchina virtua­le, semplificando notevolmente la struttura del programma.

 

                 Naturalmente, nella realizzazione effettiva la seconda richiederà un'analisi separata del sottoproblema ordina, che può però venire effettuata in modo indipendente senza complicare la struttura principale ed addirittura in un tempo e da una persona diversa. Sarà sufficiente accordarsi sul modo in cui comunicheranno tra loro le due unità di programma, quella 'principale' e quella 'subalterna'.

 

                La suddivisione gerarchica dell'analisi era già possibile anche con altri linguaggi; il merito del Pascal è stato quello di sottoporla a vincoli che impongono l'osservanza di schemi concettuali estremamente rigorosi con la rigida osservanza di ambienti operativi locali per ogni unità di programma.

 

                Un ulteriore elemento di grande interesse è la struttura a blocchi, che permette di definire procedure come oggetti interni, o privati di un'altra procedura, mentre di norma tale possibilità è riservata ai dati; il prezzo da pagare è qualche difficoltà nella definizione di possibili oggetti pubblici della stessa natura, spesso necessari per molte applicazioni.


 

                Vi erano le premesse per una affermazione universale; a suo svantaggio giocavano però molti fattori: il 'mercato' già conquistato e stabilizzato da altri linguaggi, la loro capacità di evolversi assimilando concetti e tecniche nuove e non ultime molte resistenze dovute forse ad un eccesso di arroganza e fideismo nella presentazione del  Pascal come la panacea universale per i mali della programmazione. Fattori tutti che non avrebbero avuto grande peso a lungo termine, se nello stesso Pascal non vi fossero stati problemi intrinseci; tra i più signi­ficativi vi sono:

 

                - scarse disponibilità di Input/Output, tali da rendere quasi autocontradditorio il dialogo interattivo;

                - alcune scelte tecniche troppo restrittive; ad esempio le notevoli diffi­coltà di una definizione ragionevole

                  delle stringhe di caratteri;

                - altre anche troppo comprensive, come la possibilità di ridefinire i nomi standard per le costanti predefinite

                  e per i tipi base dei dati.

 

                A questo va aggiunto un contesto poco intuitivo: pure senza considerare l'immediatezza del BASIC, il FORTRAN consente sperimentazioni significative anche dalle fasi iniziali dell'apprendimento; il Pascal richiede invece un notevole grado di stabilizzazione concettuale per potere passare alla scrittu­ra del primo programma. Ciò è certamente corretto in astratto, ma è in pratica un ostacolo consistente per i primi approcci con il linguaggio, che sono quelli maggiormente condizionanti.

 

                Nonostante la definizione estremamente rigida del linguaggio, e forse proprio a causa sua, si è poi avuto un ulteriore problema: ogni costruttore intenzionato a mettere sul mercato una versione di Pascal è stato costretto ad operare aggiunte e modifiche, in particolare per i primi due dei tre punti citati sopra, che hanno inevitabilmente condotto a situazioni di larga incom­patibilità, particolarmente paradossale per un linguaggio nato con l'intenzio­ne di stabilire uno standard universale.

 

                Tutto ciò ha marcato la rapida ascesa, ma l'altrettanto rapido declino del Pascal, da molti oggi considerato un ottimo strumento didattico per l'ap­prendimento dei principi di programmazione, ma che nella pratica risulta largamente superato da altri, tra i quali il protagonista principe è l'ultimo di cui ci occupiamo.

 

 

 

 

            1.11 - Un possibile punto d'arrivo: il C.

 

                Il linguaggio C, che evidenzia già dal nome la predilezione dei suoi autori per la sintesi, si è evoluto da un precedente linguaggio B (e presumi­bilmente da un A) parallelamente al sistema operativo Unix, di cui era parte integrante ed allo stesso tempo strumento di costruzione.

 

                Esso è stato sviluppato in un periodo in cui la proliferazione di lin­guaggi e sistemi operativi generava una confusione non indifferente, per di più con soluzioni spesso legate a contesti specifici, che i costruttori tende­vano a rendere esclusivi per favorire la massima dipendenza dei clienti dalla scelta iniziale di macchina e linguaggio.

 

                Lo scopo era quello di costruire un sistema operativo ed un linguaggio integrati tra loro e totalmente indipendenti dalla configurazione fisica  della implementazione (realizzazione effettiva delle procedure), in modo da potere trasferire il software da una macchina all'altra senza difficoltà.

 

                Il tentativo ha avuto successo, anche se in tempi relativamente lunghi; Unix e C non sono lo standard accettato da tutti, ma la tendenza è alla cre­scita continua ed è favorita dalla comparsa delle nuove macchine a tecnologia RISC, luna delle novità più consistente dell'inizio degli anni '90.

 

                Il C ha già conquistato, ad esempio, una buona quota dell'utenza scien­tifica tradizionale  del FORTRAN,  che il Pascal aveva toccato solo marginal­mente. Esso è inoltre lo standard di fatto per le procedure di controllo industriale e per l'automazione, per lo sviluppo di sistemi operativi, per la scrittura di compilatori di altri linguaggi, che ne stanno di conseguenza assimilando buona parte delle modalità operative.

 

                Vi sono quindi buoni motivi per ritenere che possa diventare il linguag­gio di programmazione, specialmente nelle più recenti varianti C++, pure non sottovalutando l'inerzia dell'utenza e le capacità di adattamento degli altri linguaggi.

 

                Le idee guida del C sono per molti aspetti simili a quelle del Pascal, con l'accentuazione della divisione di un programma in funzioni da considerare come operazioni astratte o virtuali.

 

                Mantiene la richiesta di definizione esplicita per ogni oggetto trattato dal programma, ma con vincoli meno rigidi, che permettono collegamenti più facili nelle strutture modulari che dividono un programma in più testi distin­ti, come accade necessariamente in grandi progetti.

 

                Le disponibilità linguistiche descrivono in modo naturale tutte le strutture logiche, e l'insieme standard di operazioni eseguibili è tale da permettere il controllo della macchina al più basso livello possibile, in precedenza raggiungibile solo con un ASSEMBLER.

 

                La definizione base del linguaggio è quasi la minima possibile e quindi quella per cui il progetto del  compilatore è più semplice, rapido e sicuro; poiché il C è in grado di sostituire quasi completamente l'ASSEMBLER, ci si può limitare ad impiegare quest'ultimo per la sola costruzione del compilatore C e procedere poi con tutti i vantaggi di un linguaggio di alto livello. Nella realtà le cose sono più complesse, ma non di molto, se uno dei principali impieghi del linguaggio è, come accennato sopra, addirittura la scrittura dei programmi che costituiscono un sistema operativo.

 

                Nella (1.5.6) erano stati elencati gli elementi per i quali un linguag­gio di programmazione deve fornire la definizione; rispetto ad essi il C elimina addirittura le istruzioni di Input/Output, non considerate elemento standard del linguaggio, ma una opzione cui deve provvedere il costruttore del compilatore, ponendola con altri servizi in una apposita libreria.

 

                Da questo punto di vista il C è più 'povero' dei suoi concorrenti, perché riduce al minimo le parole chiave e la relativa sintassi, pure posse­dendo un insieme di operazioni molto più ampio del normale; è invece propor­zionalmente maggiore la libreria di funzioni ausiliarie che, come per ogni altro linguaggio, hanno lo scopo di evitare all'utente la continua riscrittura di segmenti sempre uguali di programma, simulando una macchina virtuale tanto più potente quanto maggiori sono i servizi di libreria.

 

                Avere lasciato libertà di costruzione negli insiemi di definizione dei dati non elementari e nelle librerie ha avuto come conseguenza la comparsa di molte versioni di C che in comune avevano solo il nome. Il grande successo del linguaggio ha però oramai condotto alla definizione di un suo standard (le norme ANSI) che lo hanno ridefinito in modo completo, in particolare per il nucleo più importante di servizi della libreria standard.

 

                Vi possono essere vecchie versioni di programmi non più in grado di funzionare secondo le nuove norme e può rendersi necessaria una revisione abbastanza approfondita. Ma la relativa 'giovinezza' del linguaggio, unita ad uno sforzo interessato di tutti i costruttori, rende tali problemi del tutto marginali.

 

 

 

 

            1.12 - Conclusioni e prospettive dei linguaggi.

 

                Dalla presentazione, forse per qualche aspetto troppo favorevole, si potrebbe dedurre che siano molto alte le probabilità che il C, specie con le nuove versioni object oriented C++, si imponga come unico protagonista.

 

                Un maggior grado di realismo porta però a correggere in principale l'aggettivo unico; non si deve infatti sottovalutare quanto accennato in precedenza sulla adattabilità degli altri linguaggi; ciò richiede anzi ulte­riori precisazioni.

 

                La previsioni di rapida eliminazione del FORTRAN da parte del Pascal non si sono mai realizzate in parte per le 'debolezze' del secondo, ma anche per la rapida assimilazione nel primo di alcune delle facilitazioni linguistiche e dei concetti presenti nel Pascal.

 

                Lo stesso è avvenuto e continua ad avvenire rispetto al C, in modo tale che le principali limitazioni del FORTRAN sono rimaste la proibizione della ricorsività per i sottoprogrammi e l'assenza della gestione della memoria dinamica, entrambe eliminate dal FORTRAN 90.

 

                Il medesimo fenomeno di assimilazione ha naturalmente interessato anche il Pascal, il BASIC ed addirittura l'ASSEMBLER, tanto che oramai molti co­struttori presentano ambienti speciali per lo sviluppo di programmi del tipo detto Quick, Turbo e simili, nei quali è possibile mescolare arbitrariamente moduli scritti in uno qualunque dei linguaggi.

 

                Sono in genere unificate le librerie di servizi matematici, di gestione del video, della memoria, della grafica, tutte ricavate dalla base fornita dal C ed utilizzabili da qualunque linguaggio; nelle versioni più recenti anche il COBOL è interessato a tale integrazione.

 

                Sembra cioè che la scelta della particolare sintassi da utilizzare debba dipendere quasi solo da una preferenza estetica, ma è perlomeno imprudente azzardare previsioni in merito.

 

                La novità di maggior rilievo è però data non da un linguaggio, ma da un nuovo modo di intendere la programmazione; si tratta della sigla OOP, per Object Oriented Programming, di cui non è ancora chiaro quali promesse potran­no trovare realizzazione nei fatti, ma le cui prospettive sembrano essere molto promettenti.

 

                Gli 'oggetti' in questione non si identificano più con i dati e le procedure operative delle impostazioni tradizionali, ma sono una mescolanza di entrambi, resi disponibili all'utente tramite la definizione di classi in cui esistono sottoclassi capaci di ereditare proprietà che non debbono quindi essere ridefinite. Da questo dovrebbe discendere la possibilità di riutilizza­re software in contesti diversi da quelli per cui era stato originariamente concepito.

 

                Non è possibile approfondire l'argomento in questa sede; esso richiede­rebbe la considerazione di linguaggi che si sono evoluti su altre linee per un diverso tipo di necessità: dBase, Oracle, Forth, Lisp, Prolog, Ada, Modula-2, Simula, SmallTalk sono alcuni dei principali nomi lungo questo cammino.

 

 

 

 

 

 

 

            1.13 - Cenno ai sistemi operativi.

 

                Avendo in diverse occasioni menzionato i sistemi operativi, è opportuno dare anche per essi un minimo di informazioni di dettaglio; anche in questo contesto si è infatti assistito ad una evoluzione che per molti aspetti ha avuto il carattere di una rivoluzione.

 

                Il sistema operativo è l'insieme di programmi di base per la gestione delle risorse fisiche che rende il computer diverso dalla semplice integrazio­ne delle sue parti e ne fa una macchina general purpose, cioè ad utilizzazione flessibile, diversa da ogni altra costruita in precedenza.

 

                Senza sistema operativo l'utente sarebbe costretto a caricare manualmen­te passo dopo passo i suoi programmi in memoria, come in effetti avveniva sui primi prototipi. Allo stesso modo dovrebbe provvedere per l'avviamento del programma, la sua sostituzione con un altro, ecc.

 

                I primi sistemi operativi si limitavano a rendere automatiche queste operazioni, essendo poco più che loader (caricatori) per semplici sequenze batch: caricamento del programma / elaborazione / stampa dei risultati.

 

                La grande differenza di velocità tra le operazioni di memoria e quelle sui dispositivi periferici (lettura di schede, stampa, ma anche accesso ai dischi ed ai nastri) ha rapidamente dato origine a sistemi operativi capaci di gestire la multiprogrammazione, cioè  la esecuzione apparentemente contempora­nea di più programmi.

 

                La competizione tra i programmi per le risorse fondamentali, memoria ed unità di calcolo soprattutto, ha richiesto una organizzazione molto accurata, con tabelle che stabiliscono lo stato corrente ed il grado di precedenza, continui avviamenti, arresti e riordinamenti, protezione reciproca, segnali per stati di possibili crisi, ecc.

 

                A questo stadio il sistema operativo era ancora piuttosto semplice e limitato nelle funzioni esterne, anche se molto complesso in quelle interne, e rimaneva legato alla 'filosofia batch', per cui un lavoro iniziato non poteva subire modifiche fino alla sua conclusione; al massimo, poteva essere inter­rotto.

 

                Un ulteriore salto di qualità si è reso necessario con la distribuzione di servizi agli utenti finali derivante dalla comparsa dei terminali video; poiché ogni utente è potenzialmente interessato ad avviare ed arrestare pro­grammi, controllarne ed eventualmente modificarne lo stato di esecuzione, trasferire dati tra dispositivi di varia natura, inviare messaggi ad altri utenti e riceverne, si deve predisporre un apposito linguaggio di comandi che metta tutto ciò alla sua portata in termini sufficientemente semplici da evitare un continuo ricorso agli specialisti.

 

                Dal punto di vista dei progettisti del sistema operativo questo comporta la scrittura di programmi di gestione molto più complessi, con strutture di dati molto articolate, che a loro volta richiedono quote consistenti di risor­se della macchina (memoria, dischi, tempo di elaborazione) solo per metterla in grado di fornire le prestazioni per cui è stata progettata.

 

                I sistemi operativi di tipo interattivo e/o multiutente realizzavano tutti questi scopi, ma in generale non sono stati organizzati in modo abba­stanza semplice da evitare realmente all'utente la necessità di nozioni tecni­che, se non nel caso di operazioni di terminale ristrette all'impiego di programmi applicativi chiusi, in cui il programmatore dovrebbe avere previsto uscite controllate per tutte le situazioni anomale.

 

                Per citare un solo esempio, quello per molti aspetti più avanzato, questa era la situazione tipica dei sistemi di elaborazione Digital (PDP/RSX e VAX/VMS) all'inizio degli anni '80. 

 

                Il problema posto dalla molteplicità dei sistemi operativi è della stessa natura, e per certi aspetti assai più grave, di quelli derivanti dalla proliferazione dei linguaggi di programmazione: ogni costruttore ha proposto al mercato uno o più sistemi operativi, senza alcuna preoccupazione di comuni­cazione e compatibilità, in modo tale che il cambio di costruttore o anche solo di modello significa spesso dovere iniziare da capo l'addestramento di tutti gli addetti.

 

                Il proposito dichiarato di ogni fornitore era naturalmente quello di 'rivestire' con il miglior sistema operativo possibile la macchina di sua costruzione; quello non dichiarato era di diversificarsi il più possibile dalla concorrenza per rendere difficili successive scelte alternative da parte del cliente 'conquistato'.

 

                 I medesimi autori del linguaggio C hanno cercato di porre rimedio a questa situazione definendo un sistema operativo che fosse indipendente dalle caratteristiche specifiche di ogni macchina particolare; esso, nato con lo scopo di unificare,  è stato chiamato Unix, ed i programmi che lo compongono sono stati scritti tutti in linguaggio C 'minimo' in modo da richiedere ad ogni costruttore particolare solo la messa a punto di un compilatore C ridotto alle operazioni essenziali.

 

                Un elemento di grande interesse, presente nello Unix fin dall'inizio, è la possibilità data all'utente di modificare il comportamento del sistema operativo, personalizzandolo tramite una serie di variabili e procedure di ambiente, che possono essere modificate liberamente.

 

                Per ogni utente viene infatti avviato un processo che contiene una nuova 'copia' del sistema operativo, o shell ('guscio' in cui l'utente è idealmente confinato). Dovrebbero essere evidenti le potenzialità di questa impostazione, alla quale del resto i sistemi concorrenti si sono subito ispirati.

 

                Le fortune dello Unix sono oscillate tra alti e bassi, immediatamente compromesse dalla comparsa sul mercato di almeno due versioni con larghi settori di incompatibilità; esse sono però risalite nella seconda metà degli anni '80 per l'interesse comune di molti costruttori a definire uno standard uguale tutti, reso necessario dal forte grado di integrazione in rete raggiun­to dai sistemi fisici e dai costi della progettazione e dell'aggiornamento di un sistema di software.

 

                Anche il campo dei sistemi operativi è stato rivoluzionato dalla rapida diffusione del Personal Computer; dopo una fase transitoria caratterizzata dal massimo disordine possibile dovuto alla proliferazione di sistemi diversi, vi è stato un tentativo analogo a quello dello Unix, con la comparsa del sistema CP/M, sfortunatamente sviluppato su una configurazione di macchina rivelatasi perdente nel confronto con le altre.

 

                Limitandoci al campo dei Personal, i 'vincitori', cioè coloro che sono riusciti a stabilizzare sul mercato la presenza del loro prodotto, sono stati soltanto due: il più importante è il sistema MS-DOS (MicroSoft Disk Operating System) con cui la IBM ha deciso di equipaggiare la propria configurazione di Perso­nal, che è divenuto rapidamente lo standard anche per altri costruttori; il sistema minoritario è invece quello con cui la Apple Computer, prota­gonista principale nella prima fase di espansione, ha equipaggia­to la propria macchina di seconda generazione, denominata Macintosh.

 

                Non consideriamo invece casi come quello dei Commodore Amiga, degli Atari e simili, dotati di sistemi operativi diversi e la cui diffusione è limitata quasi solo al settore home computer.

 

                Dei due citati, il sistema MS-DOS è nato in forma 'tradizionale', come un insieme di servizi richiamabili da appositi comandi digitati alla tastiera, quindi in forme simili a quelle dei sistemi per macchine più grandi, ed in particolare parzialmente analogo allo Unix.

 

                Ne derivano gli stessi limiti: gli utenti finali non specialisti sono posti a confronto con una forma di linguaggio tecnico piuttosto ostico; sono quindi comparsi sul mercato strumenti detti integrati, o utilities, che sono interfacce utente facilitate.

 

                Essi non sono parte dello MS-DOS, ma programmi applicativi proposti in genere da produttori indipendenti, il cui scopo principale è di evitare all'utente la scrittura delle righe di comando, sostituendole con azioni di natura più intuitiva, suggerite da elementi grafici presenti sullo schermo.

 

                Assai diverso è il caso del sistema Macintosh, progettato fin dall'ini­zio per evitare del tutto all'utente la forma tecnica dei comandi, sostituita da un uso intensivo degli elementi grafici mediante un strumento complementare alla tastiera, il mouse, capace di rappresentare in forma immediata la posi­zione e le scelte sullo schermo.

 

                Constatata la maggiore facilità d'uso di questo strumento, il suo analo­go, e cioè un ambiente grafico a finestre e basato sull'impiego di  menu' a tendina (pop-up) si è rapidamente diffuso anche in ambiente MS-DOS, per il quale sta rapidamente divenendo lo standard.

 

                Nelle versioni più recenti, l'ambiente Windows è ormai un sistema opera­tivo autonomo, che di fatto sostituisce lo MS-DOS con un insieme di programmi più adatto alle risorse messe a disposizione dalle nuove tecnologie, in parti­colare per la gestione di grandi quantità di memoria.

 

                All'inizio degli anni '90 questa impostazione è finalmente stata ripro­dotta anche nei grandi sistemi, con la definizione del protocollo, X-Windows, accettato come base comune da tutti i maggiori costruttori tramite una nuova associazione detta 'Open Software', cosa che fa sperare in una reale unifica­zione, certamente non della struttura del sistema operativo, ma almeno della sua interfaccia, cioè del modo in cui viene proposto all'utente.

 

                I sistemi operativi sono certamente gli strumenti software che risentono maggiormente della evoluzione dello hardware, o che in certi casi debbono addirittura precederla.

 

                Due esempi significativi sono dati dalle architetture di macchine vir­tuali e di reti locali o remote.

 

                Nel primo caso le richieste degli utenti sono rivolte in astratto ad un gruppo (cluster) di macchine che si autogestiranno nel decidere istante per istante chi utilizza determinate risorse; l'utente non sa, cioè, quali unità a dischi, memorie ed unità centrali lo stiano effettivamente servendo. Qualcosa di non molto diverso si potrebbe dire per macchine ad architettura parallela, dotate cioè di più di un microprocessore centrale.

 

                Nel secondo caso le macchine collegate in una rete restano in genere indipendenti, ma possono cooperare a diversi livelli, condividendo risorse periferiche (stampanti, dischi), mettendo in esecuzione programmi ottenuti in copia (download) da un altro elaboratore, ecc.

 

                Poiché i sistemi operativi costituiscono da un lato l'interfaccia con l'utente, ma dall'altro sono i gestori delle risorse della macchina, è ovvio che ambienti così complessi e diversificati pongano problemi ai progettisti dei sistemi.

 

                Ogni sistema, completo e coerente al suo interno deve, ad esempio, essere messo in grado di dialogare con sistemi diversi, con possibili richie­ste di traduzioni automatiche da un interprete dei comandi ad un altro, da una interfaccia grafica ad un'altra.

 

                Gli orientamenti attuali vanno verso sistemi polimorfi, in grado di 'simularsi' l'un l'altro in architetture 'aperte', ove l'utente possa sceglie­re tra diversi ambienti quello che gli è più congeniale.