Introduzione alla programmazione

Introduzione alla programmazione: storia, variabili, dati, funzioni e paradigmi

Questo articolo introduce il lettore alle basi della programmazione, l’insieme dei processi che concepiscono, sviluppano ed eseguono programmi informatici per risolvere problemi o gestire le informazioni. I codici di esempio non sono presi esplicitamente da nessun linguaggio in particolare ma servono soltanto per capire come si scrivono le istruzioni.

Sin dall’antichità l’uomo ha sempre ideato metodi per automatizzare i calcoli e processi ripetitivi. Uno degli esempi più semplici è l’abaco, inizialmente una semplice tavoletta dove si spargeva della polvere di sabbia che veniva spostata per tracciare le operazioni matematiche o le figure geometriche e usata presso diversi popoli orientali e dai Greci. Successivamente si passo all’abaco a colonne dove elementi di natura diversa potevano essere disposti su colonne per rappresentare visivamente addizioni o sottrazioni.

Secoli dopo, nel 1617, John Napier conosciuto anche come Giovanni Nepero, ideò dei metodi per effettuare moltiplicazioni e divisioni complesse. Il primo consisteva nel sommare i logaritmi a base 10 dei due numeri e ricavare la potenza di quella base usando la somma ottenuta come esponente.

I primi calcolatori erano completamente meccanici e formati da ingranaggi o ruote dentate collegate tra loro. Quando una ruota superava la cifra 9, spostava la ruota successiva per aggiungere una decina e così via. Ecco perché i primi calcolatori complessi erano molto grandi, in quanto i loro componenti richiedevano molto spazio.

Gradualmente, si iniziò ad adottare il sistema binario, formato soltanto dai simboli 0 e 1. Infatti, qualsiasi numero decimale poteva essere rappresentato usando soltanto questi due simboli. Nel 1854, George Boole sviluppò un sistema logico basato su due stati dove il simbolo 1 rappresentava lo stato di vero mentre lo 0 rappresentava lo stato di falso. Inoltre furono introdotti le operazioni AND quando due stati sono entrambi veri, OR che verifica se almeno uno stato è vero e NOT che nega la prima proposizione.

Si passò così a dei calcolatori elettromeccanici che utilizzavano i relè, componenti formati da un elettromagnete che generava un campo magnetico durante il passaggio di corrente e rappresentando lo stato 1 o 0, un braccio mobile per aprire o chiudere i contatti con un altro relè. Dato che ogni relè rappresentava un bit, un macchinario che eseguiva calcoli molto complessi doveva essere molto grande e occupare molto spazio.

Vennero anche introdotte le schede perforate, dei semplici pezzi di cartone o di plastica con una serie di fori che potevano essere perforati. Questo è il primo esempio di programmazione, in quanto a seconda della posizione dei fori, si potevano scrivere le istruzioni per il calcolatore che accendeva i relè o li teneva spenti.

L’evoluzione che portò ad avere i computer su larga scala fu l’invenzione dei transistor, piccolissimi componenti elettronici semiconduttori che potevano accendersi e spegnersi collegati tra loro. In questo modo lo spazio necessario per effettuare i calcoli divenne insignificante al punto che persino i dispositivi dalle dimensioni di una mano sono in grado di agire come un computer anche se meno potente rispetto ad un dispositivo fisso.

I linguaggi di programmazione hanno semplificato di molto il modo in cui l’uomo dà delle istruzioni alla macchina. Infatti, questi linguaggi si servono della sintassi e della grammatica inglese, una lingua comprensibile all’uomo e soltanto dopo la converte nel sistema binario e la trasmette al cervello del computer.

Input, elaborazione ed output

Innanzitutto per effettuare i calcoli è sempre necessario disporre di tre cose. Uno strumento che inserisce i dati, un cervello che effettua le elabora e un mezzo che mostra i risultati. Persino l’uomo può agire da calcolatore: immaginiamo quando operiamo o risolvevamo a scuola un’espressione matematica. Leggevamo tutta l’espressione, sceglievamo le operazioni da fare in base alla priorità e scrivevamo la nuova riga sotto con i risultati. Continuavamo così fino a quando l’espressione era completata. Le mani agivano da input, il foglio mostrava i dati da elaborare o elaborati.

Anche i computer più avanzati funzionano grazie ai dati, aspetti elementari di entità e fenomeni. Se vogliamo che un sito web mostri il catalogo dei nostri prodotti, il codice deve sapere innanzitutto che cos’è un prodotto, il nome, il suo codice univoco, una descrizione, il prezzo e altre informazioni. Quando un cliente scrive una recensione, il codice la conserva sottoforma di dati che possono essere mostrati o filtrati.

Per introdurre i dati al computer si utilizzano mouse, tastiera, gamepad, touchpad, la voce mentre per mostrare i dati in uscita, l’elaboratore manda i dati su un monitor oppure comunica a voce.

Variabili e tipi di dato

I dati vengono conservati in variabili, una sorta di etichette con un nome descrittivo in genere molto esplicito per aiutare il programmatore a ricordare cosa deve essere trattato. Le variabili possono contenere stringhe di testo, numeri, valori booleani, e tipi di dato creati appositamente dall’utente.

Per creare nuovi tipi di dato, il programmatore fa uso di classi, di funzioni o di oggetti a seconda del linguaggio usato e dallo scopo. Per creare un tipo di dato che conserva le informazioni delle auto, si può creare una classe chiamata Auto contenente variabili come nome, anno, marche e modello.

Le funzioni sono un insieme di istruzioni con un nome che indica il loro scopo; sono una sorta di sottoprogramma che può essere richiamato più volte senza bisogno di riscrivere tutte le istruzioni ogni volta. Quando un programmatore si trova a ripetere più volte determinate istruzioni, spesso decide di creare una funziona apposita.

Per inserire delle informazioni che non vanno usate dal programma ma servono soltanto per aiutare il programmatore a ricordare o sapere a cosa serve il codice ciascun linguaggio usa simboli diversi prima del testo, ad esempio //.

//Dati e istruzioni principali
nome_utente = chiedi('Inserisci il tuo nome')
utente1 = new Utente(nome_utente)

//Funzioni richiamabili
function chiedi(testo) {
  riquadro.testo = testo
  return riquadro.testo
}

//Struttura di un nuovo tipo di dato
class Utente {
  constructor(nome) {
    this.nome = nome
  }
}

Operatori aritmetici, logici e di confronto

Gli operatori sono dei simboli usati per effettuare operazioni aritmetiche, assegnare valori a delle variabili, per fare dei confronti.

Gli operatori aritmetici sono gli stessi che usiamo nelle calcolatrici: possiamo sommare, sottrarre, moltiplicare e dividere due numeri con i simboli + , * / mentre per ottenere il resto di una divisione usiamo il simbolo %.

Gli operatori di assegnazione permettono di assegnare un valore ad una variabile. Il valore principale è il simbolo = ma possiamo combinarlo con quelli aritmetici, semplificando le operazioni aritmetiche.

Gli operatori di confronto paragonano due proposizioni e ritorneranno i valori true o false, a seconda se la condizione che noi chiediamo viene soddisfatta oppure no. I simboli sono:

  • == verifica se due valori sono uguali mentre === confronta anche i tipi
  • != verifica se due valori sono diversi mentre !== confronta anche i tipi
  • > che significa “maggiore di” mentre >= sta per “maggiore o uguale a”
  • < che significa “minore di” mentre <= sta per “minore o uguale a”

Gli operatori logici sono delle congiunzioni tra due proposizioni e hanno i seguenti simboli:

  • &&: ritorna true se entrambi i valori sono veri;
  • ||: ritorna true se soltanto un valore è vero;
  • !: ritorna true se il valore che stiamo valutando è falso.
    num1 = chiedi('Inserisci primo numero')
    num2 = chiedi('Inserisci secondo numero')

    somma = num1 + num2
    differenza = num1 - num2
    prodotto = num1 * num2
    quoziente = num1 / num2
    resto = num1 % num2

    numero_stringa = '2'
    numero = 2

    stesso_valore = num1 == num2 //true
    stesso_valore_tipo = num1 === num2 //false

    num1 > num2 ? alert(num1 + ' maggiore') : alert( num2 + ' maggiore')

    congiunzione = stesso_valore && stesso_valore_tipo //false
    disgiunzione = stesso_valore || stesso_valore_tipo //true
    negazione = !stesso_valore_tipo //true

Istruzioni condizionali e cicli

Per aiutare il programma a capire come procedere a seconda dei casi si possono usare delle istruzioni condizionali o cicli. Le condizioni sono degli eventi che devono essere soddisfatti. Innanzitutto il codice da eseguire viene inserito dentro delle parentesi graffe e sono scritte in sequenza dal primo comando all’ultimo. Questo insieme di istruzioni dentro le parentesi viene chiamato blocco di istruzioni. Possiamo gestire i blocchi da eseguire stabilendo determinate condizioni. Possiamo dire al programma “SE la condizione è vera ESEGUI il blocco, ALTRIMENTI esegui quest’altro blocco”. Oppure possiamo dire al programma di eseguire determinate istruzioni fino a quando una condizione viene soddisfatta. Per farlo usiamo le parole inglesi if, else, for, while e switch.

La condizione if è molto semplice: dentro le parentesi tonde scriviamo la condizione da valutare; il blocco di istruzioni viene eseguito solo se la condizione viene soddisfatta. Possiamo aggiungere else per indicare cosa fare nel caso la condizione non viene soddisfatta e aggiungere altre condizioni if se necessario.

if(utente_loggato) {
  Apri_Pagina_Profilo()
} else {
  Apri_Pagina_Login()
}

Il ciclo for esegue un blocco di istruzioni per un determinato numero di volte, mentre il ciclo foreach prende gli elementi di un insieme di valori conservati in una variabile permettendoci di manipolarli. Ad esempio, ci permette di creare una lista di valori e inserirli nella nostra pagina HTML senza dovere scrivere tutto il codice manualmente.

    for (let index = numero; index < 10; index++) {
        Mostra(index); //Funzione ipotetica che mostra un messaggio in una finestra o riquadro
    }

    lista_auto =[        
       Ford = 'Ford',        
       Peugeot = 'Peugeot'    
   ]      

   lista_autoauto.forEach(auto => {
        Mostra(auto);    
   });

Il ciclo while esegue le istruzioni fino a quando la condizione indicata come parametro viene soddisfatta. Se non facciamo nessuna modifica, il codice verrà eseguito sempre.

Il ciclo do-while esegue sempre l’istruzione la prima volta per poi valutare se la condizione per continuare risulta soddisfatta.


    while (numero < 60) {
        Mostra(numero);
        //Aumenta il numero di 1
        numero++ 
        //Se non aumenti il numero il ciclo continua all'infinito.
    }

    do {
        //Questo blocco di codice viene sempre eseguito la prima volta
        Mostra(numero); 
        numero++
    } while (numero < 70);

In entrambi i cicli, dobbiamo trovare un modo per disattivare il blocco. Ad esempio, se diciamo di eseguire un codice fino a quando un numero è minore di 10, dobbiamo trovare il modo per modificare la condizione. Un modo semplice è aumentare di uno il numero dentro il ciclo. Se il programma esegue la stessa istruzione un numero infinito di volte, si bloccherà.

Algoritmi e paradigmi di programmazione

La sequenza di istruzioni date al programma per effettuare un’operazione viene chiamato algoritmo. Lo schema o lo stile che definisce la struttura e l’organizzazione del codice viene chiamato paradigma.

Ogni linguaggio di programmazione è stato progettato per gestire situazioni diverse. Alcuni sono in grado di creare nuovi programmi mentre altri si limitano a eseguire comandi che gli diamo anche se noi non sappiamo come facciano.

Ad esempio, quando lavoriamo con i database usiamo il linguaggio SQL. Non creiamo nuove funzioni piuttosto usiamo i comandi già pronti per aggiungere, rimuovere, aggiornare o cancellare i dati che ci servono. Anche il linguaggio HTML usato per creare le pagine web funziona allo stesso modo. Non aggiungiamo funzioni, a meno che non usiamo un linguaggio aggiuntivo, ma diciamo soltanto la struttura e il contenuto della pagina.

Uno dei paradigmi più usati in programmazione è quella a oggetti (OOP). In questo caso organizziamo il codice a oggetti che rappresentano cose reali o astratte in grado di interagire con loro. Ogni oggetto ha delle proprietà e dei comportamenti tramite metodi o funzioni. Il vantaggio di questo schema è che possiamo creare altri oggetti che possono ereditare le sue proprietà e comportamenti con l’aggiunta di altri. Possiamo creare una classe generica per i nostri prodotti, ma anche classi per ogni tipologia con proprietà e metodi extra. In questo modo non dobbiamo ricopiare tutto il codice della classe genitore.