Didattica Gambas: Gestione errori (parte 2)


Come promesso nel precedente post ora vedremo alcuni esempi dell’uso delle funzioni che Gambas offre per la gestione degli errori.

Immaginiamo ad esempio di voler eliminare un file il cui percorso è contenuto nella variabile di tipo stringa di nome $indirizzo. La prima cosa da fare e indicare, mediante il comando KILL il file da eliminare:

KILL $indirizzo


Così come è scritta l’istruzione, non si potrà mai sapere se essa sarà eseguita con esito positivo o se solleverà un’eccezione. Si usa pertanto la seguente sintassi:

TRY KILL $indirizzo


In questo modo diciamo a gambas di
tentare l’esecuzione di KILL e di restituirci l’eventuale errore se esso dovesse presentarsi. Come si fa allora ad analizzare l’esito? Come detto in precedenza si ricorre al valore che in questo momento assumerà ERROR. Essa potrà valere o TRUE, sapremo così che c’è stato un errore, o FALSE, esplicando la riuscita dell’istruzione.

Si usa pertanto la seguente sintassi:

IF ERROR THEN PRINT "Errore nell'istruzione kill"


Si vede facilmente che IF analizza lo stato di ERROR e se esso è TRUE allora stamperà nel terminale la stringa racchiusa tra gli apici.

Immaginiamo ora di voler sapere quale errore in particolare si sia presentato. Per il nostro scopo basterà utilizzare le funzioni interne alla classe Error.

Analizziamo la seguente sintassi

TRY KILL $indirizzo
IF ERROR THEN PRINT Error.Text


Con queste due righe di codice abbiamo detto a gambas di provare a rimuovere il file $
indirizzo e di scrivere nel terminale il testo dell’errore, se presente, così come esso viene restituito dal sistema. Infatti Error.Text conterrà il testo dell’errore qualora esso esista.
In modo analogo possiamo analizzare il codice colpevole dell’errore e il punto del sorgente in cui esso si è presentato. Basterà infatti analizzare rispettivamente le funzioni Error.Code ed Error.Where. Un esempio di codice potrebbe essere:

TRY KILL $indirizzo
IF ERROR THEN
PRINT "Testo errore: " & Error.Text
PRINT "Codice errore: " & Error.Code
PRINT "Errore presente in: " & Error.Where
END IF

L’uso combinato di TRY ed ERROR è molto semplice e permette al programmatore di ovviare con facilità ad eventuali problemi che potrebbero causare il crash del programma.

Vediamo ora l’uso di FINALLY e CATCH

Come si è detto FINALLY, posto prima di un blocco di codice, permette di eseguirlo ignorando gli errori che invece di essere analizzati vengono semplicemente propagati fino alla fine del blocco. L’uni modo che si ha per analizzare gli errori è l’uso di CATCH. Vediamo un codice d’esempio prelevato dalla documentazione di gambas e leggermente modificato:

SUB PrintFile($indirizzo AS STRING)

DIM hFile AS File
DIM $Stringa AS STRING

OPEN FileName FOR READ AS #hFile

WHILE NOT EOF(hFile)
LINE INPUT #hFile, $Stringa
PRINT $Stringa
WEND

FINALLY ' Lo esegue sempre
CLOSE #hFile

CATCH ' Esegue solo se c'è un errore
PRINT "Non è possibile stampare il file "; $indirizzo

END


Il codice è facilmente comprensibile. Esso si limita all’apertura di un file di testo da stampare riga per riga nel terminale. Solo alla fine si usa FINALLY per provare a chiudere il file. Se tale operazione non è consentita (e solo in quel caso) esegue l’istruzione che succede CATCH.

Anche l’uso di queste ultime due istruzioni è tanto semplice quanto potente e permette di scrivere sempre codice di ottima qualità con strumenti di facile utilizzo.

Didattica Gambas: Gestione degli errori


Quando si programma in Gambas molto spesso si fa l’errore di dare per scontato che una determinata azione andrà sempre a buon fine e che pertanto sarà eseguita in tutti i casi.

Essendo Gambas un linguaggio diverso dai suoi simili di più basso livello, tipo C, non si ha molto la cognizione della gestione degli errori e delle eventuali anomalie che possono presentarsi da situazione a situazione e da macchina a macchina.

Non prevedere gli errori significa dare in mano all’utente finale un programma instabile che potrebbe crashare miseramente per una nostra leggerezza nel codice.

Vediamo un pò gli strumenti che il gambero offre per cercare, intercettare e gestire gli errori.

TRY

Try, che letteralmente vuol dire “prova”, è un’istruzione utile a intercettare eventuali errori che potrebbero presentarsi sul codice che proviamo ad eseguire.

Immaginiamo ad esempio di voler aprire un file. Aprire un file è un operazione che può fallire per diversi motivi, mancanza di spazio in memoria, file inesistente o errori di sintassi del codice. Sarebbe per buona norma pertanto usare try prima del codice di gestione.

Come facciamo allora a scoprire per quale motivo il nostro codice non ha funzionato?
Per tale scopo ci viene in aiuto il successivo strumento: Error.

ERROR

Error non è un’istruzione ma è una variabile di tipo booleano (ovvero che può assumere solo il valore TRUE, cioè 1 logico, o FALSE, cioè 0 logico). Essa avrà valore 1 se nel codice analizzato da try si è presentato un errore mentre varrà 0 se il codice ha svolto il suo lavoro.

Error non è solo una variabile ma con lo stesso nome si indica anche una classe, sempre correlata all’esecuzione di try, che gestisce l’errore in ogni suo aspetto.
Tra le sue proprietà vediamo in particolare:

1) Code:
Richiamabile da Error.Code, restituisce il codice del sorgente Gambas che ha generato l’errore;

2) Text:
Richiamabile da Error.Text, restituisce il testo dell’errore così come si presenta al sistema;

3) Where:
Richiamabile con Error.Where, indica la parte del codice (Form, classe, modulo, rigo) in cui è avvenuto l’errore.

FINALLY

Finally è una particolare istruzione che posta prima di un blocco di codice forza l’interprete ad eseguirlo anche se si presentano errori. Qualora dovesse presentarsi un errore, esso sarà ignorato e si propagherà fino alla fine del blocco mentre il codice sarà eseguito, dove possibile, o ignorato. Per intercettare alla fine gli errori presentatisi si ricorre ad un’altra istruzione: Catch

CATCH

Catch è posto prima di un blocco di codice adibito alla gestione degli errori solitamente propagatisi per via della presenza di Finally.

Nel prossimo post vedremo alcuni esempi dell’uso di quste istruzioni che dovrebbero diventare uno strumento da utilizzare in maniera adeguata nei propri codici.

Didattica Gambas: I vettori


Un vettore (o array) è una struttura dati che può essere vista come un contenitore di dati tutti uguali accessibili mediante un indice. Un vettore, infatti, contiene dati dello stesso tipo accomunati da uno stesso nome ma catalogati con un indice diverso.

Un vettore può essere immaginato come una serie di celle contigue tutte uguali accessibili mediante un indice che nella maggior parte dei casi è numerico, i valori di tale indice sono consecutivi e il primo elemento del vettore ha solitamente indice pari a 0 o, in alcuni casi, 1.

Gambas, come ogni altro linguaggio di programmazione, permette l’uso di vettori diversi per ogni tipo di dato che è capace di interpretare. A differenza di altri linguaggi, però, un array in Gambas non potrà contenere mai più di 64 elementi e perciò una dichiarazione del tipo:

hArray AS Integer [65]

provocherà un errore del tipo Too many arguments (troppi argomenti). In casi come questi è utile “spezzare” il vettore in due parti gestite tramite codice dal programmatore.

Iniziamo ora ad analizzare le proprietà degli array.

BOUNDS : letteralmente limiti; è di sola lettura e restituisce una classe virtuale, di tipo .array.bounds, che rappresenta il limite di dimensione per ogni array.

COUNT : di sola lettura; restituisce un intero che rappresenta il numero di elementi presenti nel vettore (come Length).

DATA : restituisce un puntatore al dato indicato contenuto nel vettore. Per poter usare tale proprietà il dato in questione non deve essere rimosso dal vettore altrimenti il puntatore perde il riferimento.

DIM : restituisce un intero che rappresenta la dimensione completa dell’array.

LENGTH : di sola lettura; restituisce un intero che rappresenta il numero di elementi presenti nel vettore (come Count).

MAX : di sola lettura; restituisce l’indice dell’ultimo valore dell’array. E’ molto utile in fase di eliminazione dell’ultimo elemento o di gestione di cicli.

TYPE : di sola lettura; restituisce un intero che indica il tipo di dato che può essere inserito nell’array.

Si può facilmente notare come ad esempio che la proprietà max può essere ricavata da (array.count – 1) , ovvero il numero di elementi dell’array decrementato poichè il primo di essi ha indice 0.

Passiamo ora alla visualizzazione dei metodi applicabili ai vettori.

ADD : aggiunge un elemento a quelli già esistenti nel vettore. Questo metodo crea appositamente per il dato una nuova “cella” e pertanto dopo l’uso di add l’array avrà un elemento in più.

CLEAR : pulisce l’array. Nel caso di vettori monodimensionali esso elimina il contenuto dello stesso e porta la sua dimensione a 0 mentre nel caso di array multidimensionali porta il valore di tutti gli elementi a 0 o NULL ma lascia inalterata la dimensione della struttura.

COPY : restituisce una copia del vettore. E’ possibile specificare anche se si vuole copiare solo un certo numero di elementi.

DELETE : rimuove uno o più elementi dall’array e ne restituisce il puntatore.

EXIST : restituisce il booleano 1 (true) se il valore indicato è contenuto in un elemento dell’array, altrimenti restituisce 0 (false).

EXTRACT : svolge la stessa funzione di delete.

FILL : riempe il vettore con il valore specificato. Se nessun altro parametro e specificato allora riempe tutto l’array, se si specifica start imposta solo quel valore se si specifica anche length allora imposta tutti i valori a partire da start per una lunghezza pari a length.

INSERT : inserisce un array in un altro partendo dalla posizione indicata. Se tale valore non è indicato allora l’array verrà aggiunto di default alla fine.

POP : rimuove l’ultimo elemento dall’array e lo restituisce. Questa operazione ridimensiona l’array eliminando anche lo spazio occupato dall’elemento cancellato. Bisogna accertarsi che il vettore abbia almeno un elemento prima di usare pop poiché un array vuoto provoca errore.

PUSH : inserisce un nuovo elemento alla fine dell’array allocando anche una nuova cella per esso. Si così un incremento dei numeri di elementi.

REMOVE : rimuove uno o più elementi dall’array ridimensionando anche la struttura con relativo decremento del numero di elementi.

RESIZE : ridimensiona il numero di elementi dell’array e quindi lo spazio occupato in memoria. Se l’array viene ridotto allora gli elementi eliminati saranno quelli posti alla fine (quelli con indice più alto), se l’array è espanso allora gli elementi verranno posti alla fine e a loro sarà dato un valore di default da inizializzare qualora serva.

REVERSE : capovolge l’ordine degli elementi dell’array. Molto utile nel caso di cambio di tipo di ordine in un array ordinato.

Questa è una semplice vetrina di ciò che Gambas può fare con gli array. Questo ovviamente non pone freno alla fantasia di chi può, con due righe di codice, far fare molte più cose a questo linguaggio.