(Parte 9)
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.
Secondo esercizio
Il secondo esercizio richiede la realizzazione di una procedura in grado di richiamare
quella appena illustrata per calcolare la somma dei valori assoluti di 3 numeri passati
come parametri per valore. La soluzione banale ed rappresentata dal codice riportato
di seguito:
Sub SommaVAssoluti(ByVal n1 As Double, ByVal n2 As Double, ByVal
n3 As Double, ByRef Somma As Double)
Dim r1 As Double
Dim r2 As Double
Dim r3 As Double
ValAssoluto n1, r1
ValAssoluto n2, r2
ValAssoluto n3, r3
Somma = r1 + r2 + r3
End Sub
Anche in questo caso, il risultato restituito al blocco di codice chiamante per mezzo di un
parametro passato per riferimento.
Le funzioni
Un sensibile miglioramento della leggibilit del codice e della comodit d'uso dello
strumento di sviluppo deriva dalla possibilit di restituire un valore evitando l'uso di una
variabile globale o di un parametro passato per riferimento. Ci possibile per mezzo
delle funzioni. Il linguaggio prevede una quantit elevatissima di funzioni standard. Ad
esempio, per calcolare il valore assoluto di un numero, esiste la funzione Abs, che riceve
in ingresso un dato numerico e ne restituisce il modulo. La riga
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>,
... <definizione_parametro_n>)] As <tipo>
[<dichiarazione_variabili_locali>]
<istruzione_1>
...
<istruzione_n>
<nome>=<valore>
End Function
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.
La ricorsione
Si supponga di voler realizzare una funzione in grado di calcolare il fattoriale di un numero
intero. Ricordando che il fattoriale definito solo per valori numerici positivi o nulli (in
quest'ultimo caso giova ricordare che il fattoriale di 0 1), possibile prevedere la
seguente implementazione:
Function Fattoriale(ByVal n As Integer) As Long
Dim i As Integer
Dim Risultato As Long
If n >= 0 Then
Risultato = 1
For i = 2 To n
Risultato = Risultato * i
Next i
Else
Risultato = 0
End If
Fattoriale = Risultato
End Function
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.
L'algoritmo appena descritto non l'unico in grado di effettuare il calcolo del fattoriale di un
numero. Ad esempio, possibile scrivere la seguente implementazione:
Function Fattoriale(ByVal n As Integer) As Long
If n >= 0 Then
If n = 0 Then
Fattoriale = 1
Else
Fattoriale = n * Fattoriale(n - 1)
End If
End If
End Function
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
Calcola = n + Calcola(n - 1)
End Function
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.
bene tuttavia non abusare della ricorsione. Infatti, sebbene in alcuni casi semplifichi
notevolmente il compito del programmatore, talvolta pu comportare un sensibile aumento
della richiesta di risorse da parte del sistema, data la necessit che esso ha di mantenere
contemporaneamente attive pi istanze della stessa funzione.
Esercizio
Si provi a realizzare una funzione che, dato un parametro n intero positivo passato per
valore, sia in grado di restituire la somma dei primi n numeri naturali. A tal fine si faccia
uso della ricorsione.
La procedura Main
Lo studio delle subroutine termina con una procedura un po' particolare, la cui importanza
tutt'altro che trascurabile. Si tratta della procedura Main.
Un'applicazione realizzata in Visual Basic generalmente dotata di un'interfaccia utente
grafica, in cui l'interazione con gli elementi attivi determina il flusso del programma.
Tuttavia, in alcuni casi, soprattutto per la realizzazione di semplici utility in grado di
operare in modo invisibile all'utente, necessario sopprimere l'interfaccia grafica. Quando
ci avviene, il progetto risulta privo di form. Il codice deve pertanto essere posto altrove,
ovvero all'interno di moduli. Affinch una sequenza di istruzioni sia eseguita all'avvio di
un'applicazione necessario inserirla all'interno di una procedura denominata Main.
Occorre inoltre selezionare tale routine come oggetto di avvio nella finestra delle propriet
del progetto in luogo di un form. Una semplice procedura Main la seguente:
Sub Main()
If Date$ = "12-25-1998" Then
MsgBox "Buon Natale"
End If
End Sub
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
Conclusioni
Le procedure e le funzioni sono strumenti estremamente efficaci, in grado di fornire un
notevole aiuto al programmatore. I moderni linguaggi di programmazione orientati agli
eventi, come Visual Basic, si fondano in modo pressoch totale sulla presenza di tali
strutture.
L'acquisizione della necessaria dimestichezza nel loro uso diventa pertanto un obbligo per
colui che desidera sfruttare al meglio le potenzialit dello strumento. Per questo motivo,
ancora una volta la lezione si chiude rivolgendo al lettore un invito ad esercitarsi sugli
argomenti trattati, servendosi a tal fine anche degli esercizi proposti.