Salta al contenuto principale

Corso visual basic script/Accorgimenti per ridurre la probabilità di errore

Guido Ruggeri su winguidotecnica, 15\01\2010, h. 14.43.

Negli ultimi esercizi che avete svolto, avete cominciato a
rendervi conto di quanto sia facile confondersi o sbagliare
mentre si scrive un codice sorgente.
Basta scrivere una lettera al posto di un altra, oppure
diverso al posto di uguale, ed ecco che il funzionamento del
programma è compromesso.
Banali errori possono arrivare così a vanificare tutto il
lavoro di progettazione del programma.
Così oggi apriamo una parentesi per parlare di quali
accorgimenti conviene prendere per ridurre le probabilità
di commettere errori.
Dico ridurre, perché annullarle è impossibile. Per non
commettere errori, alla fine, c'è soltanto un modo: porre
molta attenzione quando si lavora, controllare il lavoro col
massimo scrupolo, svolgere quanto più possibile prove di
funzionamento.
Comunque, abbiamo due sistemi che ci permettono di avere un
maggior controllo sul risultato del nostro lavoro.
1. fare abbondante uso dei commenti;
2. abilitare la dichiarazione obbligatoria delle variabili.
Cominciamo quindi a parlare dei commenti.
I commenti sono delle annotazioni che possiamo liberamente
inserire all'interno del nostro codice sorgente, scrivendoci
quello che vogliamo.
Non fanno parte del flusso del programma, perciò in fase
di esecuzione l'interprete li ignora. Infatti i commenti
servono soltanto a noi nella fase di scrittura del codice
sorgente.
Sono molto utili per documentare il programma che scriviamo,
cosa molto utile soprattutto per il caso in cui quel codice
sorgente debba poi essere usato anche da altri
programmatori.
Il nostro interprete VBScript identifica l'inizio di un
commento con la parola Rem.
Rem è l'abbreviazione della parola inglese "remark".
Quando una riga inizia con Rem, quella riga, in fase di
esecuzione, è come se non ci fosse.
Facciamo un esempio.

Ed ora, un po' di pubblicità

:

Rem Qui inizia il programma
Cognome = "Ruggeri"
Rem ho assegnato il mio cognome, sotto forma di stringa,
alla variabile Cognome
Nome = "Guido"
Rem ho assegnato il mio nome, sotto forma di stringa, alla
variabile Nome
Msgbox "Io mi chiamo: " Nome & " " & Cognome
Rem ho fatto apparire in una finestra il contenuto della
variabile Nome
Rem concatenato a quello della variabile Cognome, facendoli
precedere
Rem dalla dicitura introduttiva "Io mi chiamo: "
Rem Qui finisce il programma.

Se salviamo queste righe in un file .vbs e lo eseguiamo, il
programma viene eseguito normalmente, come se le righe che
iniziano con Rem non ci fossero.
La parola Rem, scomoda da usare, può essere sostituita con
il più comodo segno dell'apice. Quello che, nella tastiera
italiana, è a destra dello 0.
Così possiamo più semplicemente scrivere:

' Qui inizia il programma
Cognome = "Ruggeri"
' ho assegnato il mio cognome, sotto forma di stringa, alla
variabile Cognome
Nome = "Guido"
' ho assegnato il mio nome, sotto forma di stringa, alla
variabile Nome
Msgbox "Io mi chiamo: " Nome & " " & Cognome
' ho fatto apparire in una finestra il contenuto della
variabile Nome
' concatenato a quello della variabile Cognome, facendoli
precedere
' dalla dicitura introduttiva "Io mi chiamo: "
' Qui finisce il programma.

Non necessariamente un commento deve occupare un'intera
riga. I commenti si possono scrivere anche alla fine di una
riga, dopo le istruzioni di programma, senza andare a capo.
Così:

' Qui inizia il programma
Cognome = "Ruggeri" 'ho assegnato il mio cognome, alla
variabile Cognome
Nome = "Guido" 'ho assegnato il mio nome, sotto forma di
stringa, alla variabile Nome

L'uso dei commenti aiuta a evitare di commettere errori. Ad
esempio, quando si hanno dei blocchi If - End If nidificati
tra di loro, di quelli che quando iniziano a complicarsi non
ci si raccapezza più niente.
Facciamo un esempio, agganciandomi ad uno degli ultimi
esercizi che abbiamo svolto:

'Inizio del primo blocco If
If Risposta = "Garibaldi" Then
MsgBox "Risposta esatta"
Else 'caso Else relativo al primo blocco If
'Il secondo blocco if è nidificato nel caso Else del
primo blocco If
'Inizio del secondo blocco If
If Risposta = "garibaldi" Then
MsgBox "Risposta esatta, ma avresti dovuto scriverla
con l'iniziale maiuscola"
Else 'caso Else relativo al secondo blocco If
MsgBox "Risposta errata"
End If 'Chiusura del secondo blocco If
End If 'Chiusura del primo blocco If
'Fine del programma

Adesso parliamo della dichiarazione obbligatoria delle
variabili.
Abbiamo già detto che VBScript è abbastanza elastico, e
non ci obbliga a dichiarare preliminarmente le variabili di
cui fa uso il nostro programma.
Le istruzioni per dichiarare le variabili sono: Dim, Public,
Private.
Lasciamo da parte, per ora, le ultime due, e consideriamo
l'istruzione Dim.
Abbiamo visto che possiamo iniziare un programma
direttamente così:

Cognome = "Ruggeri"
Nome = "Guido"

ma è più ordinato farlo iniziare con la dichiarazione
delle variabili di cui il programma farà uso. Così:

Dim Cognome
Dim Nome
Cognome = "Ruggeri"
Nome = "Guido"

In entrambi i casi, supponiamo che, andando avanti, mi
sbaglio a scrivere la variabile Cognome.
Ad esempio, scrivo:

Msgbox "Io mi chiamo: " & Nome & " " & Congome

Ho scritto Congome, con la n prima della g, anziché
Cognome. Insomma, ho scritto Cognome in mariese.
Se non me ne accorgo, quando si andrà ad usare il
programma, apparirà la scritta:

"Io mi chiamo: Guido "

Non appare il cognome, perché la variabile che ho
concatenato nell'argomento di Msgbox è Congome, non
Cognome. E Congome, per l'interprete, è una variabile
diversa da Cognome e mai usata prima, e perciò non
contiene nessun valore.
Questo succede sia se non ho dichiarato le variabili, sia se
le ho dichiarate. Infatti, in entrambi i casi, la variabile
Congome, mai dichiarata e mai usata prima, non contiene
nulla.
Insomma, c'è un errore nel programma, di cui però
rischio di non accorgermi, perché, nonostante l'errore, il
programma funziona.
Quando lo vado a provare, se non ci presto sufficiente
attenzione potrei benissimo non accorgermi che nella
finestra viene solo il nome senza il cognome.
Ma supponiamo che io dica all'interprete: voglio che la
dichiarazione delle variabili sia obbligatoria.
In tal caso, l'interprete si accorgerebbe che Congome è
una variabile che non dovrebbe esistere, perché non è
stata dichiarata.
Perciò, tentando di eseguire il programma, otterremmo un
messaggio di errore, che ci direbbe:
Variabile non definita: 'Congome'.
Avremmo così la possibilità di individuare dove sta
l'errore e di correggerlo.
Avremmo, è vero, delle seccature in più, perché il
programma non potrebbe partire finché tutte le variabili
non fossero regolarmente dichiarate. Ma avremmo anche un
maggior controllo su quello che stiamo scrivendo, con la
possibilità di accorgerci se abbiamo scritto male qualche
variabile.
L'istruzione per abilitare la dichiarazione obbligatoria
delle variabili la dobbiamo scrivere all'inizio del
programma. L'istruzione è:

Option Explicit

Quindi il nostro programma diventa:

Option Explicit
Dim Cognome
Dim Nome
Cognome = "Ruggeri"
Nome = "Guido"
Msgbox "Io mi chiamo: " & Nome & " " & Congome

In questo modo, se nell'ultima riga scrivo erroneamente
Congome, il programma non parte nemmeno. Ho così modo di
rendermi conto che qualcosa non va.
Allora, ricordiamoci:
Option Explicit
come prima riga,
poi dichiarare tutte le variabili con Dim.
E' così che si riduce la possibilità di fare errori di
scrittura.

d.

> chiaro.
> ma una domanda
> tu dici che le dichiarazioni delle variabili vanno messe
> all'inizio.e attivare l'Option Explicit ma mettiamo il
> caso che io scrivessi.
>
> Option Explicit
> Dim Nome
> Dim Cognome
> nome = "Antonio"
> Cognome = "De Angelis"
> MsgBox "Io mi chiamo: " & nome & cognome
> se volessi continuare questo programma scrivendo anche la
> mia età. posso continuare scrivendo
>
> Dim Anni
> anni = ""39"
> MsgBox "Ed ho: " & anni & ", anni."
> ho la dichaiarzione dim anni la devo mettere
> obbligatoriamente all'inizio?

r.

Di questo avevamo già parlato.
Le dichiarazioni non devi necessariamente metterle tutte
all'inizio, tuttavia, per una questione di ordine, è bene
abituarsi a farlo.
Invece l'istruziome Oprion Explicit, quella si, va messa
all'inizio.
***
d.

non so se l'ing. condivide ma credo che vada messo così:

Option explicit
Dim N1
Dim N2
Dim N3
N1= 5000 'cifra massima
N2= csng(inputbox("somma esborso"))
n3= 500 ' cifra minima
If N2 lettura mi pareva tutto a posto, ma alla prova qualsiasi
> cifra si scriva risulta fuori range, anche quelle che in
> realtà sono corrette. Sotto le accludo il testo
integrale:
> Option explicit dim N1
> dim N2
> dim N3
> N3=5000
> N2= inputbox( "inserire cifra")
> N1= 500
> If N2>N1 Then 'Inizio primo blocco If
> Msgbox "La cifra " & N2 & " è fuori range"
> Else 'Caso Else del primo blocco If
> If N2 primo Msgbox "La cifra " & N2 & " è fuori range"
> Else 'Caso Else del secondo blocco If
> Msgbox "La cifra: " & n2 & " è nel range previsto"
> End If 'Chiusura secondo blocco If, nidificato nel primo
> End If 'Chiusura del primo blocco If

ma alla prova qualsiasi cifra si scriva risulta fuori range,

Risposta:
Ovviamente.
Rispetto a come l'avevi scritto la prima volta, hai
invertito due variabili.
La prima volta avevi posto:
N1= 5000 'cifra massima
n3=500 ' cifra minima
Adesso invece hai posto:
N3=5000
N1=500
Se scambi le varibili, allora devi anche scambiare tutti i
loro riferimenti nel programma.
Quindi ad esempio, la prima istruzione condizionale deve
diventare:
If N2>N3
anziché
If N2>N1

d.

. una variabile numerica definita ma non assegnata, vale 0
Risposta:
Non è proprio così.
O meglio, potrebbe esserlo in altre versioni di Basic o in
altri linguaggi, dove abbiamo la possibilità di assegnare
alle variabili anche il tipo di valore che sono destinate a
contenere.
Per esempio, in altre versioni possiamo scrivere:
Dim A as Integer
In questo modo, obblighiamo la variabile A ad essere
numerica intera, e quindi il suo valore predefinito diventa
0.
Ma in VBScript questo non esiste: le variabili, anche se le
dichiariamo, sono tutte di tipo Variant, cioè possono
accettare qualsiasi tipo di valore.
Quindi una variabile definita ma non assegnata non vale 0,
perché 0 sarebbe già un valore numerico.
Invece la variabile non assegnata è Empty, cioè: vuota.
Per Empty si intende una variabile di tipo Variant che non
ha contenuto.
Però, nel momento in cui tu vai ad impegnare una variabile
Empty in un calcolo aritmetico, ecco che alla variabile
Empty viene automaticamente fatto corrispondere il valore
numerico equivalente, cioè 0.
Allor stesso modo, se la vai ad impegnare in un
concatenamento di stringhe, ecco alla variabile Empty viene
automaticamente fatta corrispondere una stringa vuota.
Facciamo una prova.
Esiste una funzione che ci permette di testare se una
variabile è Empty, cioè se non è mai stata assegnata.
Quella funzione si chiama: IsEmpty.
Prova allora a scrivere:

If IsEmpty(A) Then MsgBox "La variabile A è vuota"

Se la esegui senza aver mai assegnato la variabile A, il
messaggio ti appare.
Se invece prima hai eseguito sulla variabile A una qualsiasi
istruzione di assegnazione, anche A = 0, il messaggio non
ti appare.

***

Quello che ha scritto Alessandro va bene.
Aggiungo qualche osservazione.

Messaggio originale:
Da : Alessandro Ricotta
Ricordiamoci che il valore restituito dalla
funzione InputBox è sempre una stringa. Quindi il valore
memorizzato nella variabile N2 va convertito in numero
prima di essere confrontato con gli altri due, altrimenti
l'interprete eseguirà un confronto fra stringhe benchè i
valori restanti siano numeri. E noi sappiamo che il
confronto tra stringhe è diverso da quello fra numeri.
Ecco perchè, a mio avviso, non riesci a ottenere i
risultati desiderati.
Osservazione:
E' giusto che sia una buona abitudine da prendere, quella di
convertire sempre al tipo appropriato i valori ottenuti con
certe funzioni come InputBox, che restituiscono stringhe.
E' una cosa che, a farla, non costa nulla e ci assicura di
non sbagliare. Quindi, nel dubbio se farla o no, conviene
farla subito e non pensarci più.
Ma è anche vero che, in un esercizio come questo, non era
determinante.
Infatti la variabile N2 viene usata per dei confronti con le
variabili N1 ed N3, che contengono numeri. Inoltre viene
usata per concatenarla a stringhe negli argomenti di MsgBox.
Finché gli usi sono questi, anche non facendo la
conversione il programma funziona lo stesso. Infatti, nei
confronti, trattandosi di confronto tra stringa e numero, lo
stesso interprete penserà a convertire la stringa in un
numero prima di eseguire il confronto, mentre nei
concatenamenti a stringhe il fatto che sia già una stringa
è in realtà un vantagggio, perché l'interprete si
risparmia di doverla convertire da numero a stringa.
Quindi non si può attribuire alla mancata conversione il
non funzionamento del programma.

Messaggio originale:
C'è anche da aggiungere che tu hai
confuso per semplice distrazione le variabili N1 ed N3,
sbagliando nel fare il confronto.
Risposta:
Infatti conviene sempre segliere, per le variabili, nomi
appropriati, per non confondersi.
Sarebbe stato meglio scrivere così:

Nmin = 500
Nmax = 5000

e chiamare semplicemente N il numero da confrontare.
Aggiungo anche che, in questo caso, conviene definire Nmin e
Nmax come costanti, anziché come variabili.

Const Nmin = 500
Const Nmax = 5000

***
Alessandro Pannocchi.

> Ecco come credo di aver risolto il problema, poi guido
> dirà la sua:
>
> Option Explicit
> Const spaz = " ", Vuota = ""
> Dim Max
> Dim Min
> Dim Cifra
> Max = 5000
> Min = 500
> Cifra = InputBox("immetti un numero ")
> If Cifra = vuota then Cifra = 0
> Cifra = CSng(Cifra)
> If Cifra >= Min Then
> If Cifra <= Max Then
> MsgBox "Il numero " & Cifra & " è compreso
nell'intervallo
> ammesso." Else
> MsgBox "Il numero " & Cifra & " supera il valore massimo
> ammesso." End If
> Else
> MsgBox "Il numero " & Cifra & " è inferiore al valore
> minimo ammesso." End If
>
> in una prima versione avevo chiamato InputBox così:
> Cifra = CSng(InputBox("Immetti un numero: "))
> Ma in questo modo mi dava errore se non inserivo alcuna
> cifra. Per questo ho optato per la soluzione che ho
> proposto più sopra, che ha il vantaggio di non dare
> errori. La ripeto qui:
>
> Cifra = InputBox("immetti un numero ")
> If Cifra = vuota then Cifra = 0
> Cifra = CSng(Cifra)
>
> Infatti, quando il programma si accorge che la variabile
> cifra è vuota, le assegna il valore 0, per cui la
funzione
> CSng accetta questo valore senza dare problemi, in quanto
> anche lo zero è un numero e quindi può essere
manipolato
> dalla funzione suddetta. Purtroppo, allo stato attuale
> delle nostre conoscenze, non si riesce ad evitare che CSng
> o un'altra qualsiasi funzione di conversione in valore
> numerico, dia un errore se, al posto di un numero si
> digitano delle lettere. Provatelo e sappiatemi dire che ve
> ne pare. Saluti.
Guido Ruggeri.

Molto bene, con l'esempio di Alessandro stiamo cominciando
ad introdurre qualche primo concetto di controllo sull'input
dell'utente.
Cioè: assicurarci che quello che l'utente scrive
corrisponda a ciò che ci aspettiamo.
Teniamo presente che la InputBox, che stiamo usando, è una
di quelle funzioni vecchio stampo del Basic.
Non corrisponde, cioè, ad una logica di programmazione ad
oggetti, e perciò non ci permette di imporre, fin dalla
fase di scrittura da parte dell'utente, le condizioni che
vorremmo. Ad esempio, che l'utente possa digitare soltanto
numeri e non lettere.
Insomma, è una funzione povera, che il linguaggio mette ad
uso proprio dei programmatori principianti come noi,
perché semplice e immediata da usare.
Dobbiamo quindi cavarcela eseguendo dei controlli a
posteriori, sul risultato che la funzione ci restituisce.
Uno di questi può essere appunto quello che ha fatto
Alessandro:

Const Vuota = ""
If Cifra = vuota then Cifra = 0

Quando avremo parlato di manipolazione delle stringhe,
vedremo che abbiamo la possibilità di fare di meglio.

d.

spiega un pò, grazie:
> Const spaz = " ", Vuota = ""
> significa che sia spaz che vuota sono costanti? Si possono
> quindi elencare più costanti sulla stessa riga
> separandole con la virgola?
Risposta:
Si, si può fare.
Così come anche si possono dichiarare più variabili con
un'unica istruzione Dim, in un'unica riga, separandole con
virgole:
Dim Nome, Cognome, Nominativo, A, B, C
Io però lo sconsiglio. Crea problemi in fase di modifica
del programma.

d.

> giocherellando con il programma che ho inviato stasera, mi
> sono accorto che immettendo un numero decimale, scritto
> secondo la convenzione anglosassone, cioè con il punto
per
> separare la parte intera da quella decimale, il programma
> ignora il punto e considera il numero come intero: 500.2
> viene conteggiato come 5002 Anche facendo:
> Cifra = InputBox("Immetti un numero ")
> Cifra = CSng(Cifra)
> MsgBox Cifra
> si ha lo stesso effetto, mentre usando la virgola va tutto
> a posto. Chi me lo spiega?
r.

Bada bene che tu stai parlando di dati scritti dall'utente
nel campo di editazione presente nella finestra di dialogo
che si apre in conseguenza della chiamata a InputBox.
Perciò, se rappresentano numeri, devono rispettare le
convenzioni internazionali valide per il computer in uso.
Nel nostro caso, quelle italiane.
Perciò: il separatore delle cifre decimali è la virgola,
mentre il punto funge da separatore delle migliaia e
perciò viene ignorato.
Diverso è il caso dei valori numerici che il programmatore
scrive direttamente nel codice sorgente: quelli devono
rispettare le convenzioni inglesi.
Perciò il separatore dei decimali diventa il punto.