Tipizzazione forte, oltre lo scripting

Apro, con questo articolo, una serie di suggerimenti sulla programmazione. Non è un corso, è una collezione di informazioni sperabilmente utili. Userò del codice Java quando sarà necessario fare esempi, ma esporrò concetti validi in tutti i linguaggi. Partiamo.
Quale differenza passa fra Java e JavaScript? A parte i nomi somiglianti ed una sintassi simile, tutto il resto. Ed è circa la stessa differenza che passa fra una ricetta cucinata da un famoso chef e la stessa ricetta cucinata da me. Avete mai cucinato? No? Vi svelo un segreto: al posto delle acciughe, se restate senza, si possono usare i capperi. Incredibile no? I capperi, un vegetale, al posto delle acciughe, un pesce. Certo, un vero chef probabilmente non lo farebbe mai, ma io sì.
Allo stesso modo in Java, ovvero un qualsiasi linguaggio con tipizzazione forte, non potete scambiare gli ingredienti a piacimento, mentre in JavaScript, un linguaggio con tipizzazione debole, potete. Bene, ma quando si programma, quali sono gli ingredienti? Naturalmente i dati in input del programma, o della singola funzione, o ancora della singola istruzione. I dati elaborati, ovvero quelli in output, sono l’equivalente della ricetta cucinata, ed a cucinare i dati ci pensa il computer seguendo le nostre istruzioni. Il codice che scriviamo sono come le istruzioni di una ricetta, in cui insegnamo al computer come cucinare i dati. I tipi di dati sono equivalenti, più o meno, ai tipi di ingredienti. Le acciughe sono pesci, quello è il tipo di ingrediente. I capperi sono vegetali. Il mio nome è una stringa, ovvero “Lucio”. La mia età è un numero, ovvero 40, nel momento in cui sto scrivendo.
In un linguaggio con tipizzazione debole, come per esempio JavaScript, io posso calcolare la mia età usando stringhe al posto di numeri, così:
eta = "2013" - "1973";
In questo caso il linguaggio, trovando l’operatore di sottrazione, ovvero il segno meno, sa che ha bisogno di numeri per poterlo eseguire e tenta una conversione automatica in numeri delle stringhe che abbiamo messo attorno al segno meno. Questo è utile per piccoli programmi (script) dove eventuali errori in questa conversione automatica non siano catastrofici. Per esempio, supponiamo che le due stringhe “2013” e “1973” siano frutto di una digitazione da tastiera richiesta all’utente che usa il programma e supponiamo quindi che il programma serva esattamente a dire quanti anni hai. Prima ti chiede in che anno siamo, poi ti chiede in che anno sei nato ed infine ti dice quanti anni hai. Ora supponiamo anche che l’utente, mentre inserisce i dati, per sbaglio metta una lettera I maiuscola al posto della cifra 1 (uno). Ci troveremmo a fare questo calcolo:
eta = "20I3" - "I973";
Nel caso di JavaScript, tipizzazione debole, il calcolo viene eseguito comunque, ma il risultato non è quello sperato, in quanto la variabile eta a questo punto vale NaN, cioè “Not A Number”. Un valore inutile, perché eta è un “non numero” (caspita mi sembra di parlare dei “non morti” di Monkey Island…), ma che cosa sia veramente non lo sappiamo. Peggio che mai, visto che il calcolo viene eseguito comunque ed il programma non viene fermato, potremmo accorgerci di questo “non numero” molto più avanti, quando ormai è troppo tardi per scoprire la causa del problema e correggere l’errore. Supponiamo per esempio di usare l’età per scrivere il nome dell’utente in un file e di avere un file diverso per ogni età, perché stiamo organizzando le cene dei coscritti di tutte le età del nostro paese. Ad un certo punto scriveremo il nome in un file che invece di chiamarsi “coscritti40.txt” si chiamerà “coscrittiNaN.txt”. In quel file ci finiranno tutti quelli che sbagliano a digitare i numeri. E non parteciperanno quindi ad alcuna cena dei costritti. Vogliamo veramente far morire di fame le persone?
Lo stesso programma, scritto in Java o in altro linguaggio con tipizzazione forte, non eseguirebbe la sottrazione. In Java non posso proprio scrivere
int eta = "2013" - "1973";
perché è sintatticamente errato. La sintassi Java impedisce di sottrarre stringhe. Java non fa conversioni automatiche di tipo se non in casi particolari e non pericolosi. Sicuramente non converte mai automaticamente da stringa a numero. Una riga di codice come quella, in Java, non viene neppure compilata: Java non ci permette neppure di provare il programma fino a quando non correggiamo quella riga:
int anno = Integer.parseInt("2013");
int nascita = Integer.parseInt("1973");
int eta = anno - nascita;

Ecco, questo è ciò che Java ci costringe a fare, ovvero ci costringe a scrivere esplicitamente il codice per convertire da stringa a numero intero. Lo fa perché è brutto e cattivo? Lo fa perché è antiquato? No, lo fa perché è un linguaggio con tipizzazione forte. E così facendo, da una parte scarica sul programmatore la responsabilità di eventuali errori di conversione, dall’altra può bloccare il programma e darci tutte le informazioni del caso, se quello che stiamo cercando di convertire non è convertibile nel tipo di dato che ci serve. Il principio è quello del “fail fast”, ovvero ottenere informazioni sugli errori prima possibile, in modo da poterli correggere (richiedere all’utente di digitare correttamente l’anno) prima che sia troppo tardi.
È evidente che il codice Java è più lungo, tre righe al posto di una sola. È anche evidente che il codice Java è più preciso, spiega passo passo cosa stiamo facendo. E, infine, risulta evidente come il programma sia più robusto, ovvero come sia più difficile fregarlo e mandarlo in una condizione di errore non prevista: Java fa di tutto per costringerci a prevedere le condizioni di errore. Resta un dubbio: come fa Java a bloccare il programma nel caso in cui non si possa tradurre la stringa in un numero intero? Solleva un’eccezione, ma di questo vi parlerò la prossima volta.