Corso di
Visual Basic di Maurizio Crespi
La nona lezione del corso dedicato alla programmazione in Visual Basic si pone lo scopo di illustrare le funzioni definibili dall'utente e il concetto di ricorsione Nella scorsa lezione sono state descritte le subroutine e sono stati evidenziati i benefici che il loro uso dà al programmatore. Questo mese l'argomento sarà ulteriormente approfondito con l'introduzione delle funzioni, ovvero di procedure in grado di restituire un valore senza l'ausilio di una variabile globale o di un parametro passato per riferimento, nonché con la descrizione dell'uso avanzato che è possibile fare di esse. Prima però è opportuno compiere un passo indietro per riportare alla mente i concetti esposti nella precedente puntata del corso. Come sempre, il fine è raggiunto mediante l'illustrazione delle soluzioni degli esercizi in essa proposti. Le soluzioni degli esercizi della
scorsa lezione Primo esercizio Sub ValAssoluto(ByVal Numero As Double, ByRef
Risultato As Double) Si noti che il numero di cui deve
essere calcolato il valore assoluto è fornito alla procedura tramite un parametro passato
per valore. r=0 Un eventuale tentativo da parte della routine di modificare il dato fornitole come primo parametro non ha effetto sulla variabile n posta nel blocco di codice chiamante. Diverso è invece il discorso per quanto riguarda la variabile r. Essa, infatti, è passata come parametro per riferimento; la procedura può quindi intervenire direttamente sul suo valore. Ciò permette alla routine di restituire un dato senza far uso di variabili globali. Secondo esercizio Sub SommaVAssoluti(ByVal n1 As Double, ByVal n2 As Double, Anche in questo caso, il risultato è restituito al blocco di codice chiamante per mezzo di un parametro passato per riferimento. Le funzioni x = Abs(y) fa sì che alla variabile x sia assegnato il valore assoluto del numero contenuto nella variabile y. Come accade per le procedure, è possibile incrementare l'insieme delle funzioni disponibili creandone ad hoc per soddisfare le proprie esigenze. A tal fine è necessario racchiudere le istruzioni in strutture dichiarate per mezzo della parola chiave Function, secondo la sintassi di seguito riportata: [Public|Private] Function <nome>
[(<definizione_parametro_1>, Com'è possibile notare, l'analogia
con le procedure è notevole. A differenza di esse, è necessario indicare un tipo di dati
standard al termine della riga di dichiarazione. Esso identifica il formato in cui deve
essere restituito il risultato. È inoltre necessario fare in modo che all'interno del
blocco di codice sia presente una riga che preveda l'assegnamento di un valore a una
variabile avente lo stesso nome della funzione. Tale dato è quello restituito al blocco
chiamante. Function Quadruplo(Numero As Integer) Il valore assunto dal parametro Numero
è moltiplicato per 4 e restituito dalla funzione. x = Quadruplo(y) Lo stesso scopo può essere ottenuto anche per mezzo di una procedura dotata di un parametro passato per riferimento. In questo caso il codice è il seguente: Sub Quadruplo(Numero As Integer, Risultato As
Integer) In questo caso, volendo assegnare alla variabile x il risultato, è necessario scrivere: Quadruplo(y,x) Pur essendo le due soluzioni del tutto equivalenti, appare evidente la maggiore semplicità della prima. Si noti che una funzione può restituire un solo valore. Qualora si presentasse la necessità di fornire al blocco chiamante più di un'informazione, è necessario ricorrere ai parametri passati per riferimento. Esercizio La ricorsione Function Fattoriale(ByVal n As Integer) As
Long Si tratta di una funzione in grado
di ricevere come parametro (per valore) un dato di tipo numerico intero e di restituire un
long. L'algoritmo prevede dapprima la verifica che il numero oggetto di
elaborazione sia positivo o nullo; successivamente, esegue un ciclo che provvede ad
effettuare la serie di moltiplicazioni necessaria per il calcolo del risultato. Tale
valore è infine assegnato alla funzione per fare in modo che essa lo restituisca. Si noti
che se il dato fornito in ingresso è negativo, la funzione restituisce il valore 0. Ciò
è accettabile, non essendo possibile che il fattoriale di un numero sia nullo; si tratta
quindi di un valido indicatore della presenza di un errore. Function Fattoriale(ByVal n As Integer) As
Long Il numero delle righe di codice si è ridotto, a vantaggio della leggibilità. Tuttavia, a prima vista il lettore può rimanere sconcertato dall'uso della funzione Fattoriale all'interno della propria definizione. Ciò può apparire come un errore. In realtà, tale tecnica è perfettamente lecita e prende il nome di ricorsione. Per rendersi conto del corretto funzionamento, si provi ad osservare ciò che avviene calcolando il fattoriale di un numero qualsiasi, ad esempio 3. Essendo n pari a 3, la funzione esegue il calcolo Fattoriale(3)=3*Fattoriale(2) Ma, analogamente Fattoriale(2)=2*Fattoriale(1) e Fattoriale(1)=1*Fattoriale(0) Per mezzo di una struttura If , è distinto il caso in cui n è nullo. In questa condizione la funzione restituisce il valore 1. Quindi, Fattoriale(3)=3*(2*(1*(1))) Ciò concorda con la definizione matematica del fattoriale. L'uso della ricorsione permette in alcuni casi di semplificare notevolmente la scrittura di una funzione e di migliorarne al tempo stesso la leggibilità. Tuttavia, presenta numerose insidie. Si provi a valutare il risultato prodotto dalla riga Calcola(7) dove la funzione Calcola è definita come segue: Function Calcola(n As Integer) As Integer Il risultato è costituito da un
errore di sistema. Infatti, non essendo prevista alcuna condizione di uscita, ovvero non
esistendo un valore del parametro per cui è restituito un risultato non dipendente da una
successiva chiamata della funzione, si genera una successione di invocazioni di
quest'ultima destinata a non avere fine, almeno sino all'esaurimento dello spazio di
memoria dedicato allo stack del sistema. Appare quindi evidente una condizione
fondamentale che deve essere soddisfatta da tutte le funzioni ricorsive: deve sempre
essere prevista una condizione di uscita. Esercizio La procedura Main Sub Main() Si tratta di una piccola applicazione che può essere eseguita automaticamente all'avvio di Windows e che normalmente non fornisce alcun feedback all'utente. Solo il giorno di Natale del 1998 essa ha un effetto visibile, in quanto provvede a visualizzare un messaggio di auguri. Si noti l'uso della funzione standard Date$ che restituisce una stringa contenente la data corrente. Il ricorso alla procedura Main non è tuttavia riservato solo alle applicazioni prive di form. A volte può essere utile fare in modo che un programma all'avvio sia in grado di valutare una condizione e in base ad essa scegliere fra i form che lo compongono quello che deve essere visualizzato. Si supponga di disporre di una funzione denominata SelezionaForm, di cui saranno trascurati i dettagli implementativi, in grado di leggere il registro di sistema per determinare la lingua utilizzata dalla versione in uso del sistema operativo e di restituire una stringa contenente una delle seguenti sequenze alfanumeriche: "Italiano", "Inglese", "Tedesco", "Francese". Si supponga altresì di aver realizzato un progetto caratterizzato dalla presenza di 4 form, differenti fra loro per la lingua in cui sono scritte le etichette che identificano i controlli e di aver dato ad essi rispettivamente i nomi Ita, Ing, Ted, Fra. È allora possibile scrivere una procedura Main in grado di avviare il form corrispondente alla lingua presente nel sistema. Il codice è il seguente: Sub Main() Si notino alcune particolarità; la funzione SelezionaForm, ad esempio, non prevede parametri. Affinché sia utilizzabile correttamente, è comunque necessario richiamarla specificando le parentesi, sebbene fra esse non sia posto alcun dato o nome di variabile. Si noti inoltre l'uso del metodo Show, che permette di avviare il caricamento e la successiva visualizzazione di un form. L'uso della costante predefinita vbModal accanto ad esso stabilisce che la procedura in fase di esecuzione non può passare all'istruzione successiva finché il form risulta visibile. Solo dopo la sua chiusura il flusso delle istruzioni può riprendere e, non essendo presente altro codice, il programma può terminare. Conclusioni
Maurizio Crespi si occupa principalmente di grafica e multimedia. Svolge la funzione di responsabile tecnico presso Datanord Multimedia, società specializzata nella realizzazione di software orientato al marketing e all'editoria, per la quale progetta e sviluppa applicazioni in C++, Visual Basic, Delphi e Director. Può essere contattato per e-mail come crespi@programmers.net. OTTOBRE 1998 - PROGRAMMO SUBITO n.9 |