Come trattare gli errori

Contenuto del capitolo
  • Due modi di trattare gli errori
  • Generare errori nel codice per farli raccogliere da altri.

Il modo tradizionale

Tradizionalmente quando i programmatori fanno qualche cosa, ad esempio chiamano una funzione, il risultato può essere verificato per accertarne la validità. Ad esempio se cercate di aprire un file che non esiste il risultato può essere un valore nullo. Ci sono due possibili strategie per trattare questo tipo di situazione:

  1. Inserire il codice di errore nel risultato della funzione
  2. Assegnare un valore indicante errore ad una variabile globale.

In entrambi i casi viene lasciato al programmatore il compito di verificare se si è verificato un errore ed eventualmente eseguire un'azione appropriata.

In BASIC si potrebbe fare cosí:

OPEN "A:\DATI.TXT" FOR INPUT AS #1
IF ERR = 53 THEN 
   CALL ErroreFileInesistente
ELSE
   REM SI CONTINUA CON LE OPERAZIONI SUL FILE
END IF

Questo in programmi di qualità professionale può portare ad avere oltre metà del codice dedicato a verificare il risultato di ciascuna azione per identificare errori. Questo può risultare pesante e rende il codice difficile da leggere (anche se in pratica la maggior parte dei programmi funzionano proprio cosí). Un approccio sistematico è in questo caso indispensabile ad evitare errori banali.

Il modo eccezionale

In ambienti di programmazione più recenti è stato sviluppato un modo alternativo di trattare gli errori. Questo è conosciuto come gestione delle eccezioni e funziona consentendo ad una funzione di lanciare (throw, N.d.t.) o alzare (raise, N.d.t.) una eccezione (exception, N.d.t.). Il sistema in tal caso abbandona il blocco di codice che sta eseguendo e passa al più prossimo blocco di codice per la gestione delle eccezioni. Il sistema fornisce un gestore standard che riceve (catch, Nd.t.) tutte le eccezioni e solitamente esce dopo aver scritto un messaggio di errore.

Il blocco per la gestione delle eccezioni, invece viene scritto in modo molto simile ad un blocco if...then...else:

try:
   # Qui ci va il codice per l'esecuzione normale
except EccezioneTipo1:
   # Qui ci va il trattamento per un tipo di eccezione
except EccezioneTipo2:
   # Qui ci va il trattamento per un'altro tipo di eccezione
else:
   # Qui si effettuano le operazioni per il caso 
   # in cui non si verificano eccezioni

Esiste un secondo tipo di blocco per il trattamento delle eccezioni che consente di effettuare operazioni dopo che si è verificato un errore, si tratta del blocco try...finally ed è tipicamente usato per chiudere files, trasferire buffers sul disco ecc. Il blocco finally viene sempre eseguito per ultimo indipendentemente da ciò che si è verificato nella sezione try.

try:
   # Flusso del programma normale
finally:
   # Questo viene eseguito indipendentemente
   # dal successo o dal fallimento del blocco try 

Il Tcl possiede un meccanismo simile che usa la parola chiave catch:

set codicerrore [catch {
    unset x
    } msg ]
if {$codicerrore != 0} {
    # Qui si tratta l'errore
    }

In questo caso x non esiste quindi l'istruzione unset non può essere applicata. Il Tcl lancia un'eccezione ma l'istruzione catch impedisce al programma di terminare ed invece scrive il messaggio di errore nella variabile msg e riporta un valore diverso da zero (che può essere definito dal programmatore). È possibile quindi verificare il valore definito da catch nella variabile codicerrore. Se è diverso da zero significa che si è verificato un errore ed è possibile esaminare la variabile msg per i dettagli.

Il BASIC non prevede la gestione delle eccezioni ma fornisce un costrutto che aiuta a matenere "pulito" il codice:

100 OPEN "A:\Temp.dat" FOR INPUT AS #1
110 ON ERROR GOTO 10010
120 REM QUI CI VA IL CODICE DEL PROGRAMMA
130 ...
10000 REM GESTIONE ERRORI:
10010 IF ERR = 54 THEN....

Si noti l'uso dei numeri di linea. Questa era una prassi comune nei primi linguaggi di programmazione, incluso il BASIC. Adesso è possibile ottenere lo stesso risultato usando le etichette:

ON ERROR GOTO Handler
REM Qui viene generato un errore "divisione per zero"
x = 5/0
Handler:
   IF ERR = 23 THEN 
      PRINT "E' vietato dividere per 0"
      x = 0
      RESUME NEXT
   END IF

Si noti l'istruzione RESUME NEXT che consente di tornare esattamente al punto successivo all'errore e proseguire con il programma.

Come generare errori

Supponiamo di voler generare una eccezione che debba essere ricevuta da qualcun altro, ad esempio all'interno di un modulo. In Python si usa la parola chiave raise:

numeratore = 42
denominatore = input("Per quale valore devo dividere '42'?")
if denominatore == 0:
   raise "zero denominatore"

Questo genera una eccezione di tipo stringa che può essere ricevuta da un blocco try/except.

Il Meccanismo degli errori in Tcl

In Tcl l'istruzione return accetta un'opzione -code che viene catturata da ogni istruzione catch che la racchiude:

proc prosciutto {val} {
        set x $val
        return -code 3 [expr $x]
        }
set errore [catch {
               set pippo [prosciutto 7]
               } messaggio]

errore dovrebbe assumere il valore 3 e messaggio il valore 7. Ecco un altro caso in cui la sintassi di Tcl risulta piuttosto poco intuitiva.

Il trattamento degli errori in BASIC

In BASIC è possibile assegnare un valore alla variabile ERR mediante l'istruzione ERROR:

ON ERROR GOTO ERRORI
INPUT "INTRODUCI IL CODICE DI ERRORE"; E
ERROR E

ERRORI:
IF ERR = 142 THEN
    PRINT "Generato Errore 142"
    STOP
ELSE
    PRINT "Nessun errore"
    STOP
END IF


Promemoria
  • I codici di errore possono essere verificati con istruzioni if.
  • Le eccezioni possono essere gestite con le istruzioni catch.
  • Le eccezioni possono essere generate con l'istruzione raise.
  • Gli errori possono essere rappresentati da semplici stringhe.

Precedente  Successivo  Indice


Se avete domande o suggerimenti relativi a questa pagina mandate un e-mail all'autore: alan.gauld@yahoo.co.uk o al traduttore italiano: lfini@arcetri.astro.it