Dichiarazione implicita e tipizzazione debole: gli svantaggi

Ieri chiacchieravo col mio amico Simon riguardo ai linguaggi di scripting e gli ho detto che le loro peculiarità che mi piacciono meno sono appunto quelle in oggetto. Ho deciso di descrivere il perché (e di rispondere alla sua domanda) in quest’articolo per unire l’utile al dilettevole. Si tratta naturalmente del mio parere personale, condivisibile o meno. Per gli esempi pratici farò riferimento a C++ e JavaScript, ma non sarà necessario conoscere bene questi linguaggi per capire.

Vediamo innanzitutto di chiarire le ambiguità. Prima di utilizzare una variabile in C++ dobbiamo scrivere una riga come

int numero;

e questa riga dice al compilatore che deve riservare al programma lo spazio per un numero intero, al quale ci riferiremo con la parola numero. In JavaScript non abbiamo bisogno di fare ciò: basta utilizzare la parola numero dove ci occorre per salvare degli interi, ad esempio scrivendo

numero = 5;

e il gioco è fatto. Questo è quello che intendo per dichiarazione implicita. I più attenti avranno anche notato che in C++ abbiamo detto di volere specificatamente un numero intero. Infatti un’istruzione come

numero = "Ciao mondo";

non verrà accettata dal compilatore, che rifiuterà di proseguire il proprio lavoro, se numero è dichiarata come int. Tale istruzione, viceversa, è perfettamente lecita in JavaScript, qualsiasi sia il precedente valore assegnato alla variabile. Nessuno ci impedisce di assegnarle un valore di diverso tipo. Questo è ciò che intendo per tipizzazione debole. Si noti che se tale controllo sui tipi venga fatta a tempo di compilazione (quando applicabile) o di esecuzione ai fini di questo articolo non ha alcuna importanza. Quello che conta è che in C++ dobbiamo dire esplicitamente di che tipo è la nostra variabile, mentre Javascript lo riconosce in automatico ogni volta che assegnamo un valore.

I vantaggi di queste due qualità sono evidenti: il linguaggio è più semplice ed intuitivo perché si occupa di un sacco di compiti sgraditi, di conseguenza scriveremo meno codice e più velocemente. Purtroppo però ci sono tanti svantaggi. Tanti, a mio parere, da superare i vantaggi. Vediamoli uno per uno:

  1. Errori di battitura.
    Se non dobbiamo dichiarare una variabile, qualsiasi nome utilizziamo durante il codice è lecito. Confondere le parole nuemro e numero è molto, molto facile. Javascript a volte ci viene in aiuto dicendoci che una variabile è undefined, ma se commettiamo un errore in un assegnamento gli effetti possono essere imprevedibili. Potremmo perdere molto tempo su un bug di questo genere, mentre con altri linguaggi semplicemente non ne abbiamo la possibilità.
  2. Cosa succede quando il codice cresce?
    Il codice non dovrebbe crescere tanto, dovremmo dividerlo in tanti moduli, è vero. Ma immaginiamo di aggiungere un blocco di codice nel mezzo di un file esistente. Se non siamo costretti a dichiarare le variabili può capitare di sovrascrivere un valore che serve al codice sottostante. Anche qui possono crearsi bug difficili da risolvere.
  3. Confronti
    Consideriamo il seguente frammento di codice

    numero = fetchValue('SELECT numero FROM tabella');
    if (numero == 2.5)
      print('Ho letto 2,5!');

    Se la tipizzazione è debole, diventa difficile sapere se la nostra funzione fetchValue restituirà un numero o una stringa. Ok, tanti linguaggi sono abbastanza intelligenti da restituire true se confrontiamo “2.5” con 2.5, ma questo vale sempre? Cosa succede se confrontiamo 5 con “5.0”, ecc? Difficile ricordare tutte queste regole, facile sbagliarsi! Cosa succede se la nuova versione della nostra libreria all’improvviso restituisce stringhe e non più interi? Stampando a video il valore ci sembrerà che tutto va bene, ma il nostro confronto potrebbe fallire e, tanto per cambiare, generare bug difficili da scovare!

  4. Spreco di spazio
    Niente è gratis! Perché il tipo di una variabile possa cambiare a tempo di esecuzione, devono essere tenuti più dati in memoria. Per esempio potrebbero essere necessari byte extra che dicano se la variabile è un intero, un carattere, ecc. Direte: non è grave, c’è tanta memoria ed è lo stesso con gli oggetti per permettere ereditarietà, polimorfismo e molto altro. Per cominciare, la memoria non è MAI abbastanza e poi il totale fa presto a crescere, se per esempio abbiamo un array di oggetti con diversi campi!
  5. Spreco di tempo
    Perché il linguaggio sia così comodo, deve esserci un sacco di codice che effettua controlli a tempo di esecuzione. Se confrontiamo 2.5 con “2.5” entrambi i valori devono essere controllati ed eventualmente convertiti nel tipo giusto prima che il controllo vero e proprio sia effettuato. Questo, anche se spesso non si nota, spreca cicli di CPU e rallenta l’esecuzione. In C++ ed altri linguaggi siamo costretti a scrivere il codice in modo più rigoroso. Questo sarà seccante, ma la qualità alla fine è migliore e il programma più veloce.
  6. Meno attenzione
    Per finire, prestare attenzione alla scelta dei tipi di dato giusti ci aiuta a ragionare meglio sul problema da risolvere, oltre che a scrivere un software di qualità superiore, ottimizzato nella complessità spaziale e computazionale. Non a caso, Pascal fu concepito proprio per questo e la dichiarazione delle variabili è la primissima cosa da fare quando si scrive qualsiasi (sotto)programma. Qualche maligno obietterà che pochi usano Pascal oggigiorno, ma a parte che personalmente non capisco l’astio che molti hanno nei suoi confronti, è in effetti ancora utilizzato e non solo a scopo didattico!

Ecco qui, il mio parere ve lo dato. Fatemi sapere se siete d’accordo!

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *