Differenze tra le versioni di "Scrivere una Funzione"

Da Gambas-it.org - Wikipedia.
 
(20 versioni intermedie di uno stesso utente non sono mostrate)
Riga 1: Riga 1:
Una '''Funzione''' <FONT Color=blue><SUP>[note:</sup></font> [[#Note|<SUP>1</sup>]] [[#Note|<SUP>2</sup>]] [[#Note|<SUP>3</sup>]] [[#Note|<SUP>4</sup>]] [[#Note|<SUP>5</sup>]]<FONT Color=blue><SUP>]</sup></font>  è una routine, chiamata da una routine principale, alla quale è delegato il compito di svolgere una serie di operazioni, e delle quali essa restituisce alla routine principale ''chiamante'' il risultato.
+
Una '''Funzione''' <FONT Color=blue><SUP>[note:</sup></font> [[#Note|<SUP>1</sup>]] [[#Note|<SUP>2</sup>]] [[#Note|<SUP>3</sup>]] [[#Note|<SUP>4</sup>]] [[#Note|<SUP>5</sup>]]<FONT Color=blue><SUP>]</sup></font>  è una routine, chiamata da una routine principale, alla quale è delegato il compito di svolgere una serie di operazioni, e delle quali essa restituisce il risultato alla routine principale ''chiamante''.
  
 
La Funzione è l'operazione attinente ad una fase del processo del programma.
 
La Funzione è l'operazione attinente ad una fase del processo del programma.
 +
=Dichiarazione di una Funzione=
 +
Va precisato che in Gambas <SPAN Style="text-decoration:underline">non</span> è prevista nel codice del programma la ''dichiarazione'' di una Funzione.
  
Poiché una funzione deve eseguire ''un'' compito, si ritiene non opportuno scrivere una funzione per eseguire più istruzioni insieme. E' preferibile scrivere funzioni per singoli compiti ed una ulteriore funzione che svolga l'operazione complessa, invocando le funzioni precedenti.
+
=Definizione di una Funzione=
 
+
La "definizione" della Funzione stabilisce:
 
+
* il nome (''Identificatore'' ) della Funzione medesima;
 +
* i valori in entrata, passati dalla omonima Funzione ''chiamante'', definiti «''parametri formali'' »;
 +
* il blocco delle istruzioni che compiono le operazioni necessarie per ottenere il risultato previsto dalla Funzione;
 +
* il valore di ritorno ottenuto dalla predette istruzioni operative.
 +
Gli eventuali "''parametri formali'' " di una Funzione sono posti all'interno di due parentesi tonde, nelle quali sono specificati di ciascun parametro l'identificatore e il tipo di dato.
 +
<BR>In Gambas ogni Identificatore di Funzione è consentito per una sola Funzione. Pertanto non possono esssere definite due o più Funzioni aventi il medesimo nome (identificatore).
 +
<BR> Il Blocco delle istruzionidi una Funzione rappresenta il valore permanente associato a una Funzione. In esso può essere inserita qualsiasi istruzione, compresa una chiamata di Funzione.
  
=Definizione di una Funzione=
+
La Funzione, creata dal programmatore, in Gambas è sostanzialmente ''definita'' con il seguente prototipo:
La funzione, creata dal programmatore, in Gambas è sostanzialmente definita come segue:
+
  [Public/Private] Function ''Nome_Identificativo''( [''Parametro'' As ''tipo_di_dato'', ''...idem...''] ) As ''Tipo_di_dato_ritornato''
  [Public/Private] Function ''Nome_Funzione''( ''dichiarazione dei parametri, se previsti'' As ''tipo_passato ) As ''Tipo_ritornato''
 
 
    
 
    
  ''eventuali_dichiarazioni_di_tipi_di_variabili''
+
  ''eventuali_dichiarazioni_di_tipi_di_variabili''
 
    
 
    
  ''istruzioni''
+
  ''istruzioni''
 
    
 
    
  Return ''valore_da_ritornare''
+
  Return ''valore_da_ritornare''
 
    
 
    
 
  End
 
  End
La parola chiave ''Function'', che specifica e definisce una Funzione ''chiamata'', può essere preceduta dalla parola chiave ''Public'' o ''Private'' a seconda delle necessità di visibilità della Funzione medesima.
+
La parola chiave '''FUNCTION''', che specifica e definisce una Funzione ''chiamata'', può essere preceduta dalla parola chiave ''Public'' o ''Private'' a seconda delle necessità di visibilità della Funzione medesima.
  
 
Una Funzione, per essere utilizzata dal processo del programma, deve essere invocata, chiamata da una specifica Funzione ''chiamante''. Tale Funzione ''chiamante'' deve avere un nome identificativo <SPAN Style="text-decoration:underline">identico</span> a quello della Funzione ''chiamata''.
 
Una Funzione, per essere utilizzata dal processo del programma, deve essere invocata, chiamata da una specifica Funzione ''chiamante''. Tale Funzione ''chiamante'' deve avere un nome identificativo <SPAN Style="text-decoration:underline">identico</span> a quello della Funzione ''chiamata''.
  
Inoltre, <SPAN Style="text-decoration:underline">se è previsto</span> che la Funzione ''chiamante'' passi alla Funzione ''chiamata'' uno o più valori, affinché essi vengano processati dalle istruzioni contenute dalla Funzione ''chiamata'', detti valori pasati devono essere del tipo <SPAN Style="text-decoration:underline">identico</span> a quello dichiarato nella Funzione ''chiamata''. In tal senso i valori, passati dalla Funzione ''chiamante'' sono definiti " ''argomenti'' ", mentre i valori dichiarati - e quindi poi ricevuti - dalla Funzione ''chiamata'' sono definiti " ''parametri'' ".
+
Inoltre, <SPAN Style="text-decoration:underline">se è previsto</span> che la Funzione ''chiamante'' passi alla Funzione ''chiamata'' uno o più valori, affinché essi vengano processati dalle istruzioni contenute dalla Funzione ''chiamata'', detti valori pasati devono essere del tipo <SPAN Style="text-decoration:underline">identico</span> a quello dichiarato nella Funzione ''chiamata''. In tal senso i valori, passati dalla Funzione ''chiamante'' sono definiti «''Parametri attuali'' » o «''argomenti'' », mentre i valori dichiarati - e quindi poi ricevuti - dalla Funzione ''chiamata'' (ove la Funzione è definita) sono nominati «''Parametri formali'' ».
  
La Funzione ''chiamata'' ritorna <SPAN Style="text-decoration:underline">sempre</span> un valore, che è il risultato delle operazioni svolte dalle istruzioni presenti nella Funzione. <FONT Color=blue><SUP>[note:</sup></font> [[#Note|<SUP>6</sup>]] <FONT Color=blue><SUP>]</sup></font>
+
I ''Parametri formali'' enunciati nella definizione di una Funzione, possono essere considerati come parametri ''potenziali'', nel senso che essi rappresentano il tipo di dato che la Funzione può ricevere.
 +
<BR>I ''Parametri attuali'' o ''Argomenti'' sono appunto i dati effettivamente passati alla Funzione "chiamata" attraverso la Funzione "chiamante" nello stretto rispetto dei tipi di dati attesi dalla definizione della Funzione medesima.
  
 +
La Funzione ''chiamata'' ritorna <SPAN Style="text-decoration:underline">sempre</span> un valore, che è il risultato delle operazioni svolte dalle istruzioni presenti nella Funzione. <SUP>&#091;[[#Note|<B>Nota 6</b>]]&#093;</sup>
 +
<BR>Anche il dato ritornato dall'istruzione ''Return'' può essere in sostanza considerato un parametro ''potenziale'', sebbene in questo caso in "uscita" dalla Funzione. 
  
 
Mostriamo di seguito un semplice esempio pratico con la modalità più comune di ritorno di valore:
 
Mostriamo di seguito un semplice esempio pratico con la modalità più comune di ritorno di valore:
Riga 32: Riga 42:
 
   Dim i, rit As Integer
 
   Dim i, rit As Integer
 
    
 
    
  i = 10
+
  i = 10
 
    
 
    
  <FONT Color=gray>' ''La seguente Funzione "chiamante" invoca la Funzione "chiamata" e le passa un valore come "argomento",''
+
  <FONT Color=gray>' ''La seguente Funzione "chiamante" invoca la Funzione "chiamata" e le passa un valore come "argomento", affinché sia processato, e dalla quale riceverà un valore come risultato di quel processo:''</font>
' ''affinché sia processato, e dalla quale riceverà un valore come risultato di quel processo:''</font>
+
  rit = Calcolare(i)
  rit = Calcolare(i)
 
 
    
 
    
  Print "Valore ritornato: "; i
+
  Print "Valore ritornato: "; i
 
    
 
    
 
  End
 
  End
Riga 49: Riga 58:
 
   Dim n, r As Integer
 
   Dim n, r As Integer
 
    
 
    
  n = 100
+
  n = 100
 
    
 
    
  r = valore * n
+
  r = valore * n
 
    
 
    
  Return r
+
  Return r
 
    
 
    
 
  End
 
  End
 
  
  
Riga 63: Riga 71:
  
 
In Gambas la routine principale ''chiamante'' può passare attraverso i suoi argomenti uno o più valori alla Funzione chiamata. Il passaggio degli argomenti ad una Funzione può essere di tre tipi: <SUP>&#091;[[#Note|Nota 7]]&#093;</sup>
 
In Gambas la routine principale ''chiamante'' può passare attraverso i suoi argomenti uno o più valori alla Funzione chiamata. Il passaggio degli argomenti ad una Funzione può essere di tre tipi: <SUP>&#091;[[#Note|Nota 7]]&#093;</sup>
* per ''valore'';
+
* per '''''Valore''''';
* per ''indirizzo'';
+
* per '''''Indirizzo''''';
* per ''riferimento''.
+
* per '''''Riferimento'''''.
  
  
==Passaggio per ''valore''==
+
==Passaggio per ''Valore''==
Il passaggio per ''valore'' è senz'altro la modalità più frequente di passare dei dati ad una Funzione chiamata.
+
Il passaggio per '''Valore''' è senz'altro la modalità più frequente di passare dei dati ad una Funzione chiamata.
  
Nel passaggio per "valore" viene - appunto - passato un valore o sotto forma di dato effettivo (ad esempio direttamente un dato numerico oppure indirettamente mediante una variabile - ad esempio di tipo Byte, Short, etc. - che contiene e dunque fornisce un valore.
+
Nel passaggio per ''Valore'' viene passato un valore o sotto forma di dato effettivo (ad esempio direttamente un dato numerico) oppure indirettamente mediante una variabile (ad esempio di tipo Byte, Short, Integer, etc.) che contiene e dunque fornisce un valore.
  
Con il passaggio ''per valore'' viene effettuata una ''copia'' della variabile passata alla Funzione chiamata come argomento della routine principale chiamante. Inoltre, le modifiche alla variabile del parametro passato, effettuate nella Funzione chiamata, restano confinate nell'ambito locale di detta Funzione secondaria. Ciò significa che la variabile, passata come parametro dalla routine chiamante a quella chiamata, non vede modificarsi il suo valore, nonostante la sua copia abbia subito una modifica del proprio valore a seguito di una o più operazioni nella Funzione secondaria chiamata. La viariabile presente nella routine principale chiamante resta intatta, immodificata, qualunque cosa avvenga alla sua ''copia'' nella Funzione chiamata.
+
Con il passaggio per ''Valore'' viene effettuata una ''copia'' della variabile passata alla Funzione chiamata come argomento della routine principale chiamante. Inoltre, le modifiche alla variabile del parametro passato, effettuate nella Funzione chiamata, restano confinate nell'ambito locale di detta Funzione secondaria. Ciò significa che la variabile, passata come parametro dalla routine chiamante a quella chiamata, non vede modificarsi il suo valore, nonostante la sua copia abbia subito una modifica del proprio valore a seguito di una o più operazioni nella Funzione secondaria chiamata. La viariabile presente nella routine principale chiamante resta intatta, immodificata, qualunque cosa avvenga alla sua ''copia'' nella Funzione chiamata.
 
<BR>Se, dunque, non vi fosse ritorno di valore della varibile-copia, ora con valore modificato, alla routine principale chiamante, non sarebbe possibile utilizzare nella predetta routine chiamante le modifiche apportate dalle operazioni, alle quali la Funzione secondaria chiamata è stata preposta.
 
<BR>Se, dunque, non vi fosse ritorno di valore della varibile-copia, ora con valore modificato, alla routine principale chiamante, non sarebbe possibile utilizzare nella predetta routine chiamante le modifiche apportate dalle operazioni, alle quali la Funzione secondaria chiamata è stata preposta.
 
  
 
Mostriamo un semplice esempio:
 
Mostriamo un semplice esempio:
  '''Public''' Sub Main() <FONT color=gray>' ''Routine principale''</font>
+
  Public Sub Main() <FONT color=gray>' ''Routine principale''</font>
 
   
 
   
 
   Dim a, b, risultato_di_ritorno As Integer
 
   Dim a, b, risultato_di_ritorno As Integer
 
   
 
   
  a = 2
+
  a = 2
  b = 3
+
  b = 3
 
   
 
   
 
  <FONT color=gray>' ''Chiama la Funzione, e le passa i due valori, affinché li elabori.''
 
  <FONT color=gray>' ''Chiama la Funzione, e le passa i due valori, affinché li elabori.''
 
  ' ''Alla fine la Funzione restituirà il risultato che riempirà la variabile integer "risultato_di_ritorno":</font>
 
  ' ''Alla fine la Funzione restituirà il risultato che riempirà la variabile integer "risultato_di_ritorno":</font>
  <FONT Color=#B22222>risultato_di_ritorno</font> = funzione_chiamata(<FONT color=blue>a</font>, <FONT color=blue>b</font>)
+
  <FONT Color=#B22222>risultato_di_ritorno</font> = funzione_chiamata(<FONT color=blue>a</font>, <FONT color=blue>b</font>)
 
    
 
    
 
  <FONT color=gray>' ''Mostriamo il risultato in console:''</font>
 
  <FONT color=gray>' ''Mostriamo il risultato in console:''</font>
  Print "Risultato di ritorno dalla funzione = "; risultato_di_ritorno
+
  Print "Risultato di ritorno dalla funzione = "; risultato_di_ritorno
 
   
 
   
  '''End'''
+
  End
 
   
 
   
 
   
 
   
 
  <FONT color=gray>' ''La funzione secondaria "Funzione_Chiamata" contiene il proprio nome ed i parametri come variabili dei valori passati dalla routine chiamante, e non prevede l'aggiunta della parola chiave "Sub".''
 
  <FONT color=gray>' ''La funzione secondaria "Funzione_Chiamata" contiene il proprio nome ed i parametri come variabili dei valori passati dalla routine chiamante, e non prevede l'aggiunta della parola chiave "Sub".''
 
  ' ''Essa, poiché restituisce - in questo nostro esempio - un valore Integer, termina la propria dichiarazione con "As Integer" .''</font>
 
  ' ''Essa, poiché restituisce - in questo nostro esempio - un valore Integer, termina la propria dichiarazione con "As Integer" .''</font>
  '''Private Function''' Funzione_Chiamata(<FONT color=blue>aF As Integer</font>, <FONT color=blue>bF As Integer</font>) <FONT Color=#B22222>As Integer</font>
+
  Private Function Funzione_Chiamata(<FONT color=blue>aF As Integer</font>, <FONT color=blue>bF As Integer</font>) <FONT Color=#B22222>As Integer</font>
 
   
 
   
 
   Dim somma As Integer
 
   Dim somma As Integer
Riga 107: Riga 114:
 
   <FONT Color=#B22222>Return somma</font>
 
   <FONT Color=#B22222>Return somma</font>
 
    
 
    
  '''End'''
+
  End
 
 
 
In console avremo coerentemente:
 
In console avremo coerentemente:
 
<BR>Risultato di ritorno dalla funzione = 5
 
<BR>Risultato di ritorno dalla funzione = 5
Riga 117: Riga 123:
  
 
Per ottenere da una medesima Funzione due o più risultati (quindi <SPAN Style="text-decoration:underline">senza</span> dover utilizzare una variabile globale), possiamo utilizzare due modalità:
 
Per ottenere da una medesima Funzione due o più risultati (quindi <SPAN Style="text-decoration:underline">senza</span> dover utilizzare una variabile globale), possiamo utilizzare due modalità:
* uso di una variabile vettoriale o una ''Struttura'';
+
* uso di una variabile vettoriale o di una ''Struttura'';
 
* il passaggio per ''indirizzo'' (vedi paragrafo successivo).
 
* il passaggio per ''indirizzo'' (vedi paragrafo successivo).
  
 
====Uso di un vettore come ritorno di una Funzione====
 
====Uso di un vettore come ritorno di una Funzione====
 
Mostriamo un esempio di una Funzione che ritorna per "valore" un duplice risultato mediante una variabile vettoriale:
 
Mostriamo un esempio di una Funzione che ritorna per "valore" un duplice risultato mediante una variabile vettoriale:
  '''Public''' Sub Main()
+
  Public Sub Main()
 
   
 
   
 
   Dim a, b As Integer
 
   Dim a, b As Integer
Riga 139: Riga 145:
 
   Print "Risultato (differenza) di ritorno dalla funzione = "; risultato_di_ritorno[1]
 
   Print "Risultato (differenza) di ritorno dalla funzione = "; risultato_di_ritorno[1]
 
   
 
   
  '''End'''
+
  End
 
   
 
   
 
   
 
   
  <FONT color=gray>' ''La routine Funzione, poiché restituisce - per "''Valore''" - un valore vettore Integer[], termina la propria dichiarazione con: As Integer[].''</font>
+
  <FONT color=gray>' ''La routine Funzione, poiché restituisce - per "''Valore'' " - un valore vettore Integer[], termina la propria dichiarazione con: As Integer[].''</font>
  '''Public Function''' Funzione_Chiamata(aF As Integer, bF As Integer) As Integer[]
+
  '''Public''' Function Funzione_Chiamata(aF As Integer, bF As Integer) As Integer[]
 
   
 
   
 
   Dim somma, differenza As Integer
 
   Dim somma, differenza As Integer
Riga 161: Riga 167:
 
   Return doppiorisultato
 
   Return doppiorisultato
 
   
 
   
  '''End'''
+
  End
 
 
 
In console avremo coerentemente:
 
In console avremo coerentemente:
 
<BR>Risultato (somma) di ritorno dalla funzione = 5
 
<BR>Risultato (somma) di ritorno dalla funzione = 5
Riga 168: Riga 173:
  
  
 +
==Passaggio per ''Indirizzo''==
 +
Il passaggio per '''Indirizzo''' prevede che la routine principale chiamante passi come propri argomenti alla Funzione chiamata gli ''indirizzi di memoria'' delle variabili della routine chiamante contenenti i valori che dovranno essere gestiti dalle istruzioni della Funzione chiamata. <SUP>&#91;[[#Note|Nota 8]]&#93;</sup>
  
==Passaggio per ''indirizzo''==
+
Nel passaggio per ''indirizzo'' viene - appunto - passato l'indirizzo di memoria ove è memorizzato un valore oppure un Oggetto.
Il passaggio per ''indirizzo'' prevede che la routine principale chiamante passi come propri argomenti alla Funzione chiamata gli ''indirizzi di memoria'' delle variabili della routine chiamante contenenti i valori che dovranno essere gestiti dalle istruzioni della Funzione chiamata. <SUP>&#91;[[#Note|Nota 8]]&#93;</sup>
 
 
 
Nel passaggio per "indirizzo" viene - appunto - passato l'indirizzo di memoria ove è memorizzato un valore oppure un Oggetto.
 
  
 
Il passaggio per ''Indirizzo'' di un argomento può avvenire mediante:
 
Il passaggio per ''Indirizzo'' di un argomento può avvenire mediante:
Riga 191: Riga 195:
 
====Semplici esempi pratici====
 
====Semplici esempi pratici====
 
Mostriamo un esempio pratico con un ''Vettore'':
 
Mostriamo un esempio pratico con un ''Vettore'':
  '''Public''' Sub Main()
+
  Public Sub Main()
 
    
 
    
 
   Dim vett As New Integer[4]
 
   Dim vett As New Integer[4]
 
   Dim i As Integer
 
   Dim i As Integer
 
    
 
    
  Funzione(vett)
+
  Funzione(vett)
 
    
 
    
  For Each i In vett
+
  For Each i In vett
    Print i
+
    Print i
  Next
+
  Next
 
    
 
    
  '''End'''
+
  End
 
   
 
   
 
   
 
   
  '''Private''' Function Funzione(ii As Integer[])
+
  Private Function Funzione(ii As Integer[])
 
    
 
    
 
   Dim c As Integer
 
   Dim c As Integer
 
    
 
    
    For c = 0 To ii.Max
+
  For c = 0 To ii.Max
      ii[c] = c + 1000
+
    ii[c] = c + 1000
    Next
+
  Next
 
    
 
    
  '''End'''
+
  End
 
 
 
 
 
Ora un esempio con una ''Struttura'':
 
Ora un esempio con una ''Struttura'':
 
  Public Struct STRUTTURA
 
  Public Struct STRUTTURA
Riga 225: Riga 227:
 
   
 
   
 
   
 
   
  '''Public''' Sub Main()
+
  Public Sub Main()
 
    
 
    
 
   Dim sr As New STRUTTURA
 
   Dim sr As New STRUTTURA
 
    
 
    
  Funzione(sr)
+
  Funzione(sr)
 
    
 
    
  With sr
+
  With sr
    Print .b
+
    Print .b
    Print .s
+
    Print .s
    Print .i
+
    Print .i
    Print .l
+
    Print .l
  End With
+
  End With
 
    
 
    
  '''End'''
+
  End
 
   
 
   
 
   
 
   
  '''Private''' Function Funzione(tr As STRUTTURA)
+
  Private Function Funzione(tr As STRUTTURA)
 
    
 
    
 
   With tr
 
   With tr
Riga 250: Riga 252:
 
   End With
 
   End With
 
    
 
    
  '''End'''
+
  End
 
 
 
 
 
Quindi un paio di esempi nei quali la funzione passa l'<I>indirizzo di memoria</i> di una variabile dichiarata. Per scrivere nella variabile, ricevuta come parametro di tipo ''Puntatore'' della Funzione chiamata, il risultato finale delle operazioni compiute in tale Funzione, bisognerà ovviamente utilizzare i ''Memory Stream'' unitamente alla funzione ''Write''.
 
Quindi un paio di esempi nei quali la funzione passa l'<I>indirizzo di memoria</i> di una variabile dichiarata. Per scrivere nella variabile, ricevuta come parametro di tipo ''Puntatore'' della Funzione chiamata, il risultato finale delle operazioni compiute in tale Funzione, bisognerà ovviamente utilizzare i ''Memory Stream'' unitamente alla funzione ''Write''.
  
 
Mostriamo un esempio, nel quale la funzione passa l'<I>indirizzo di memoria</i> di una variabile dichiarata di tipo ''Intero Lungo'':
 
Mostriamo un esempio, nel quale la funzione passa l'<I>indirizzo di memoria</i> di una variabile dichiarata di tipo ''Intero Lungo'':
  '''Public''' Sub Main()
+
  Public Sub Main()
 
    
 
    
 
   Dim num As Long
 
   Dim num As Long
 
    
 
    
  Funzione(VarPtr(num))
+
  Funzione(VarPtr(num))
 
      
 
      
  Print num
+
  Print num
 
    
 
    
  '''End'''
+
  End
 +
 
 
   
 
   
   
+
  Private Function Funzione(p As Pointer)
'''Private''' Function Funzione(p As Pointer)
 
 
    
 
    
 
   Dim st As Stream
 
   Dim st As Stream
 
    
 
    
  st = Memory p For Write
+
  st = Memory p For Write
  Write #st, 1234567890 As Long
+
  Write #st, 1234567890 As Long
  st.Close
+
  st.Close
 
    
 
    
  '''End'''
+
  End
 
Dello stesso tipo appena visto, il seguente esempio, ove avviene lo scambio di valori fra due variabili (''swapping''):
 
Dello stesso tipo appena visto, il seguente esempio, ove avviene lo scambio di valori fra due variabili (''swapping''):
  '''Public''' Sub Main()
+
  Public Sub Main()
 
    
 
    
 
   Dim i1, i2 As Integer
 
   Dim i1, i2 As Integer
 
    
 
    
  i1 = 1000
+
  i1 = 1000
  i2 = 2000
+
  i2 = 2000
 
      
 
      
  Scambio(VarPtr(i1), VarPtr(i2))
+
  Scambio(VarPtr(i1), VarPtr(i2))
 
      
 
      
  Print i1, i2
+
  Print i1, i2
 
    
 
    
  '''End'''
+
  End
 
   
 
   
 
   
 
   
  '''Private''' Function Scambio(x As Pointer, y As Pointer)
+
  Private Function Scambio(x As Pointer, y As Pointer)
 
    
 
    
 
   Dim z As Integer
 
   Dim z As Integer
 
   Dim st As Stream
 
   Dim st As Stream
 
      
 
      
  z = Int@(x)
+
  z = Int@(x)
 
      
 
      
  st = Memory x For Write
+
  st = Memory x For Write
  Write #st, Int@(y) As Integer
+
  Write #st, Int@(y) As Integer
  st.Close
+
  st.Close
 
      
 
      
  st = Memory y For Write
+
  st = Memory y For Write
  Write #st, z As Integer
+
  Write #st, z As Integer
  st.Close
+
  st.Close
 
    
 
    
  '''End'''
+
  End
 
 
 
 
 
Nei seguenti due esempi, invece, sarà passata una variabile di tipo ''Puntatore'' che punta ad un'area di memoria appositamente riservata.
 
Nei seguenti due esempi, invece, sarà passata una variabile di tipo ''Puntatore'' che punta ad un'area di memoria appositamente riservata.
 
<BR>In questo esempio l'area di memoria conterrà valori numerici generici:
 
<BR>In questo esempio l'area di memoria conterrà valori numerici generici:
  '''Public''' Sub Main()
+
  Public Sub Main()
 
    
 
    
 
   Dim ptr As Pointer
 
   Dim ptr As Pointer
 
   Dim c As Integer
 
   Dim c As Integer
 
    
 
    
  ptr = Alloc(SizeOf(gb.Byte), 8)
+
  ptr = Alloc(SizeOf(gb.Byte), 8)
 
    
 
    
  Funzione(ptr)
+
  Funzione(ptr)
 
      
 
      
  For c = 0 To 7
+
  For c = 0 To 7
    Print Byte@(ptr + c)
+
    Print Byte@(ptr + c)
  Next
+
  Next
 
+
  Free(ptr)
+
<FONT Color=gry>' ''Libera la memoria precedentemente allocata, affinché possa essere utiliata dal sistema:''</font>
  ptr = 0
+
  Free(ptr)
 
+
<FONT Color=gry>' ''Assegna alla variabile "Puntatore" il valore di default, affinché non punti a un indirizzo di memoria rilevante:''</font>
  '''End'''
+
  ptr = 0
 +
 +
  End
 
   
 
   
 
   
 
   
  '''Private''' Function Funzione(p As Pointer)
+
  Private Function Funzione(p As Pointer)
 
    
 
    
 
   Dim st As Stream
 
   Dim st As Stream
 
   Dim b As Byte
 
   Dim b As Byte
 
      
 
      
  st = Memory p For Write
+
  st = Memory p For Write
  For b = 1 To 8
+
  For b = 1 To 8
    Write #st, b * 10 As Byte
+
    Write #st, b * 10 As Byte
  Next
+
  Next
  st.Close
+
  st.Close
 
    
 
    
  '''End'''
+
  End
 
 
 
In quest'altro esempio sarà passata un'area di memoria contenente i valori prettamente attinenti a caratteri stringa:
 
In quest'altro esempio sarà passata un'area di memoria contenente i valori prettamente attinenti a caratteri stringa:
  '''Public''' Sub Main()
+
  Public Sub Main()
 
   
 
   
 
   Dim p As Pointer
 
   Dim p As Pointer
 
    
 
    
  p = Alloc("abcde")
+
  p = Alloc("abcde")
 
    
 
    
  Funzione(p)
+
  Funzione(p)
 
      
 
      
  Print String@(p)
+
  Print String@(p)
     
 
  Free(p)
 
  p = 0
 
 
   
 
   
  '''End'''
+
  <FONT Color=gry>' ''Libera la memoria precedentemente allocata, affinché possa essere utiliata dal sistema:''</font>
 +
  Free(p)
 +
<FONT Color=gry>' ''Assegna alla variabile "Puntatore" il valore di default, affinché non punti a un indirizzo rilevante di memoria:''</font>
 +
  p = 0
 +
 +
End
 
   
 
   
 
   
 
   
  '''Private''' Function Funzione(po As Pointer)
+
  Private Function Funzione(po As Pointer)
 
    
 
    
 
   Dim st As Stream
 
   Dim st As Stream
 
      
 
      
  st = Memory po For Write
+
  st = Memory po For Write
 
    
 
    
  Write #st, 70 As Byte
+
  Write #st, 70 As Byte
 
    
 
    
  st.Close
+
  st.Close
 
    
 
    
  '''End'''
+
  End
  
  
 
====Ritorno di più dati====
 
====Ritorno di più dati====
Come già accennato, la modalità del passaggio per ''indirizzo'' ci consente di ritornare alla routine chiamante anche più dati.
+
Come già accennato, la modalità del passaggio per ''Indirizzo'' ci consente di ritornare alla routine chiamante anche più dati.
  
 
Mostriamo un esempio pratico, nel quale vengono ritornati due dati attraverso i parametri della Funzione chiamata e di quella chiamante:
 
Mostriamo un esempio pratico, nel quale vengono ritornati due dati attraverso i parametri della Funzione chiamata e di quella chiamante:
  '''Public''' Sub Main()
+
  Public Sub Main()
 
   
 
   
 
   Dim dividendo, divisore As Integer
 
   Dim dividendo, divisore As Integer
 
   Dim p1, p2 As Pointer
 
   Dim p1, p2 As Pointer
 
   
 
   
  Print "Scrivere i valori del dividendo e del divisore."
+
  Print "Scrivere i valori del dividendo e del divisore."
  Input dividendo
+
  Input dividendo
  Input divisore
+
  Input divisore
 
   
 
   
  p1 = VarPtr(dividendo)
+
  p1 = VarPtr(dividendo)
  p2 = VarPtr(divisore)
+
  p2 = VarPtr(divisore)
 
   
 
   
  Funzione_Chiamata(p1, p2)
+
  Funzione_Chiamata(p1, p2)
 
   
 
   
  Print "Quoziente: "; Int@(p1)
+
  Print "Quoziente: "; Int@(p1)
  Print "Resto: "; Int@(p2)
+
  Print "Resto: "; Int@(p2)
 
   
 
   
  '''End'''
+
  End
 
   
 
   
 
   
 
   
  '''Public''' Function division(divid As Pointer, divis As Pointer)
+
  Private Function division(divid As Pointer, divis As Pointer)
 
   
 
   
 
   Dim i1, i2, ris As Integer
 
   Dim i1, i2, ris As Integer
 
   Dim st As Stream
 
   Dim st As Stream
 
    
 
    
  i1 = Int@(divid)
+
  i1 = Int@(divid)
  i2 = Int@(divis)
+
  i2 = Int@(divis)
  ris = i1 / i2
+
  ris = i1 / i2
 
   
 
   
  st = Memory divid For Write
+
  st = Memory divid For Write
  Write #st, ris As Integer
+
  Write #st, ris As Integer
  st.Close
+
  st.Close
 
      
 
      
  ris = i1 Mod i2
+
  ris = i1 Mod i2
 
   
 
   
  st = Memory divis For Write
+
  st = Memory divis For Write
  Write #st, ris As Integer
+
  Write #st, ris As Integer
  st.Close
+
  st.Close
 
   
 
   
  '''End'''
+
  End
  
  
===Ritorno di dati per "''Indirizzo''" senza utilizzo come argomento di un esplicito ''Puntatore''===
+
====Ritorno di dati per "Indirizzo" senza utilizzo come argomento di un esplicito ''Puntatore''====
Abbiamo visto nel paragrafo appena precedente che il ritorno di un dato attraverso i parametri (o argomenti) della Funzione prevedeva che il parametro (o i parametri, nel caso si intenda far ritornare più dati) deve essere dichiarato come tipo ''Puntatore'', dato che si tratta di passaggio dell'indirizzo di memoria della variabile, presente nella routine principale, contenente il dato da gestire nella Funzione secondaria chiamata.
+
Abbiamo visto nel paragrafo appena precedente che qualora il tipo di argomenti sia una ''Struttura'' oppure un ''vettore'', non v'è necessità che i parametri, passati alla Funzione chiamata, siano di tipo ''Puntatore'', giacché essi stessi ''puntano'' all'area di memoria degli Oggetti che rappresentano.
  
Qualora il tipo di argomenti siano una ''Struttura'' oppure un ''vettore'', non v'è necessità che i parametri, passati alla Funzione chiamata, siano di tipo ''Puntatore''.
+
Ripetiamo gli esempi con una ''Struttura'':
 
 
Mostriamo due esempi pratici.
 
 
  Public Struct STRUTTURA
 
  Public Struct STRUTTURA
 
   b As Byte
 
   b As Byte
Riga 432: Riga 431:
 
   
 
   
 
   
 
   
  '''Public''' Sub Main()
+
  Public Sub Main()
 
   
 
   
 
   Dim st As New STRUTTURA
 
   Dim st As New STRUTTURA
 
    
 
    
  With st
+
  With st
    .b = 99
+
    .b = 99
    .s = 9999
+
    .s = 9999
    .i = 999999
+
    .i = 999999
  End With
+
  End With
 
+
    
+
   Funzione_Chiamata(st)
  Funzione_Chiamata(st)
 
 
      
 
      
  With st
+
  With st
    Print .b
+
    Print .b
    Print .s
+
    Print .s
    Print .i
+
    Print .i
  End With
+
  End With
 
   
 
   
  '''End'''
+
  End
 
   
 
   
 
   
 
   
  '''Private''' Function Funzione_Chiamata(n As STRUTTURA)
+
  Private Function Funzione_Chiamata(n As STRUTTURA)
 
    
 
    
  With n
+
  With n
    .b += 99
+
    .b += 99
    .s += 9999
+
    .s += 9999
    .i += 999999
+
    .i += 999999
  End With
+
  End With
 
 
'''End'''
 
 
 
 
   
 
   
  '''Public''' Sub Main()
+
  End
 +
e con un ''Vettore'':
 +
Public Sub Main()
 
   
 
   
 
   Dim ss As String[] = ["a", "b", "c"]
 
   Dim ss As String[] = ["a", "b", "c"]
 
    
 
    
  Print ss.Count
+
  Print ss.Count
 
      
 
      
  Prova(ss)
+
  Prova(ss)
 
      
 
      
  Print ss.Count
+
  Print ss.Count
 
   
 
   
  '''End'''
+
  End
 
   
 
   
 
+
  '''Private''' Function Prova(vett As String[])
+
  Private Function Prova(vett As String[])
 
   
 
   
 
   vett.Remove(1)
 
   vett.Remove(1)
 
    
 
    
  '''End'''
+
  End
 
 
  
  
 
==Passaggio per ''Riferimento''==
 
==Passaggio per ''Riferimento''==
Il passaggio per ''Riferimento'' in Gambas prevede <SPAN Style="text-decoration:underline">sia</span> nella Funzione chiamante <SPAN Style="text-decoration:underline">sia</span> nella Funzione chiamata l'uso della parola chiave '''''ByRef''''' prima dell'argomento da passare.
+
Il passaggio per '''Riferimento''' in Gambas prevede <SPAN Style="text-decoration:underline">sia</span> nella Funzione chiamante <SPAN Style="text-decoration:underline">sia</span> nella Funzione chiamata l'uso della parola chiave '''''ByRef''''' prima dell'argomento da passare.
  
Questa modalità è una risorsa specifica e all'uopo dedicata di Gambas per passare per ''per indirizzo'' variabili che non siano già di per sé comunque dei ''Puntatori''. Infatti essa è nella sostanza identica a quella "''per Indirizzo''": non necessita dell'uso dell'istruzione ''Return'' al termine della Funzione chiamata.
+
Questa modalità è una risorsa specifica e all'uopo dedicata di Gambas per passare per ''<SPAN Style="text-decoration:underline">indirizzo</span>'' variabili che non siano già di per sé comunque dei ''Puntatori''. Infatti essa è nella sostanza identica a quella per "''Indirizzo'' ": non necessita dell'uso dell'istruzione ''Return'' al termine della Funzione chiamata.
<BR>Come già detto nel paragrafo relativo al passaggio di argomenti ''per Indirizzo'', avere un riferimento all'oggetto è molto utile in fase di passaggio tramite parametri tra un Metodo e l'altro. La modifica dell'oggetto fa sì che venga mantenuta in uscita dal Metodo, eliminando così l'obbligo del ritorno di un valore.
+
<BR>Come già detto nel paragrafo relativo al passaggio di argomenti per ''Indirizzo'', avere un riferimento all'oggetto è molto utile in fase di passaggio tramite parametri tra un Metodo e l'altro. La modifica dell'oggetto fa sì che venga mantenuta in uscita dal Metodo, eliminando così l'obbligo del ritorno di un valore.
  
 
Mostriamo un esempio:
 
Mostriamo un esempio:
  '''Public''' Sub Main()
+
  Public Sub Main()
 
   
 
   
Dim a, b As Integer
+
  Dim a, b As Integer
 
   
 
   
 
   a = 2
 
   a = 2
 
   b = 3
 
   b = 3
 
   
 
   
  Funzione_Chiamata(<FONT Color=#B22222>ByRef</font> a, b)
+
  Funzione_Chiamata(<FONT Color=#B22222>ByRef</font> a, b)
 
   
 
   
  Print "Risultato di ritorno dalla funzione = "; a
+
  Print "Risultato di ritorno dalla funzione = "; a
 
   
 
   
  '''End'''
+
  End
 
   
 
   
 
   
 
   
  '''Private''' Function Funzione_Chiamata(<FONT Color=#B22222>ByRef</font> aRif As Integer, bI As Integer)
+
  Private Function Funzione_Chiamata(<FONT Color=#B22222>ByRef</font> aRif As Integer, bI As Integer)
 
   
 
   
 
   Dim somma As Integer
 
   Dim somma As Integer
 
    
 
    
 
  <FONT color=gray>' ''Si effettua l'operazione fra i due argomenti, ed il risultato viene restituito attraverso il parametro individuato con "ByRef":''</font>
 
  <FONT color=gray>' ''Si effettua l'operazione fra i due argomenti, ed il risultato viene restituito attraverso il parametro individuato con "ByRef":''</font>
  aRif = aRif * bI
+
  aRif = aRif * bI
 
   
 
   
  '''End'''
+
  End
  
  
 
====Ritorno di più dati====
 
====Ritorno di più dati====
Anche con il passaggio per ''Riferimento'' mediante la parola chiave "''ByRef''" è possibile ritornare alla funzione chiamante due o più dati. Per fare ciò si dovrà porre la parola chiave ''ByRef'' su due o più argomenti da passare delle Funzioni chiamante e chiamata.
+
Anche con il passaggio per ''Riferimento'' mediante la parola chiave "''ByRef'' " è possibile ritornare alla funzione chiamante due o più dati. Per fare ciò si dovrà porre la parola chiave ''ByRef'' su due o più argomenti da passare delle Funzioni chiamante e chiamata.
 
 
  
  
 
=Scrivere ed invocare una Funzione in un Modulo=
 
=Scrivere ed invocare una Funzione in un Modulo=
 
La scrittura e la successiva invocazione di una Funzione in un ''Modulo'' segue la procedura normale.
 
La scrittura e la successiva invocazione di una Funzione in un ''Modulo'' segue la procedura normale.
 
  
 
Facciamo un semplissimo esempio.
 
Facciamo un semplissimo esempio.
  
 
Nella Classe principale avremo il seguente codice:
 
Nella Classe principale avremo il seguente codice:
  '''Public''' Sub Form_Open()   
+
  Public Sub Form_Open()   
 
    
 
    
Dim by As Byte   
+
  Dim b As Byte   
 
    
 
    
 
  <FONT color=gray>' ''Invochiamo la funzione nel Modulo e le passiamo un valore di tipo Byte (in questo esempio: 6 ).''
 
  <FONT color=gray>' ''Invochiamo la funzione nel Modulo e le passiamo un valore di tipo Byte (in questo esempio: 6 ).''
  ' ''Essa, a sua volta, ci passerà un valore che inseriremo nella variabile "by":''</font>
+
  ' ''Essa, a sua volta, ci passerà un valore che inseriremo nella variabile "b":''</font>
    by = Module1.funzioneNelModulo(6)
+
  b = Module1.funzioneNelModulo(6)
 
    
 
    
    Print by
+
  Print b
 
    
 
    
  '''End'''
+
  End
 
 
 
 
 
Nel Modulo avremo:
 
Nel Modulo avremo:
 
  '''Public''' Function funzioneNelModulo(a As Byte) As Byte  <FONT color=gray>' ''Riceve dalla routine chiamante un valore di tipo "Byte", ed un valore di tipo "Byte" a sua volta restituirà''</font>   
 
  '''Public''' Function funzioneNelModulo(a As Byte) As Byte  <FONT color=gray>' ''Riceve dalla routine chiamante un valore di tipo "Byte", ed un valore di tipo "Byte" a sua volta restituirà''</font>   
Riga 547: Riga 539:
 
   Dim b As Byte   
 
   Dim b As Byte   
 
    
 
    
  b = 2   
+
  b = 2   
 
    
 
    
 
  <FONT color=gray>' ''La Funzione effettua l'operazione per la quale è stata concepita:''</font>
 
  <FONT color=gray>' ''La Funzione effettua l'operazione per la quale è stata concepita:''</font>
    b = b * a   
+
  b = b * a   
 
    
 
    
 
  <FONT color=gray>' ''Restituisce, quindi, alla routine chiamante, presente nella Classe principale, il risultato dell'operazione:''</font>
 
  <FONT color=gray>' ''Restituisce, quindi, alla routine chiamante, presente nella Classe principale, il risultato dell'operazione:''</font>
    Return b
+
  Return b
 
    
 
    
  '''End'''
+
  End
 
 
  
  
Riga 570: Riga 561:
  
 
[5] Possiamo distinguere quattro tipi di ''Funzioni'':
 
[5] Possiamo distinguere quattro tipi di ''Funzioni'':
* native ed autonome. Si tratta di quelle Funzione che sussistono di per sé all'interno di Gambas, avendo così una ''dignità'' propria (ad esempio: ''Alloc()'', ''SizeOf()'', ''Max()'' e così via).
+
* native ed autonome. Si tratta di quelle Funzione che sussistono di per sé all'interno di Gambas, avendo così una ''dignità'' propria (ad esempio: "Alloc()", "SizeOf()", "Max()" e così via).
* ''metodi'' di Classi Gambas. Si tratta di quelle Funzioni di Gambas che non sono ''autonome'', ma esistono in quanto risorse tipiche di una Classe. Tali Funzioni (''Metodi'') possono essere utilizzati <SPAN Style="text-decoration:underline">solo se richiamate attraverso un Oggetto</span> di una Classe. Esempi di tali Funzioni: ''Object.<FONT Color=#B22222>SizeOf()</font>'', ''Button1.<FONT Color=#B22222>Move()</font>'', ''vettore.<FONT Color=#B22222>Push()</font>'', ''Paint.<FONT Color=#B22222>DrawImage()</font>'' e così via.
+
* ''metodi'' di Classi Gambas. Si tratta di quelle Funzioni di Gambas che non sono ''autonome'', ma esistono in quanto risorse tipiche di una Classe. Tali Funzioni (''Metodi'') possono essere utilizzati <SPAN Style="text-decoration:underline">solo se richiamate attraverso un Oggetto</span> di una Classe. Esempi di tali Funzioni: "Object.<FONT Color=red>SizeOf()</font>", "Button1.<FONT Color=red>Move()</font>", "vettore.<FONT Color=red>Push()</font>", "Paint.<FONT Color=red>DrawImage()</font>" e così via.
 
* Funzioni scritte dal programmatore (oggetto della presente pagina): sono appunto specifiche Funzioni, scritte dal programmatore, per assolvere ad un particolare compito che si esaurisce con l'applicazione, nella quale la Funzione è stata appositamente creata.
 
* Funzioni scritte dal programmatore (oggetto della presente pagina): sono appunto specifiche Funzioni, scritte dal programmatore, per assolvere ad un particolare compito che si esaurisce con l'applicazione, nella quale la Funzione è stata appositamente creata.
 
* Funzioni esterne. Tali funzioni <SPAN Style="text-decoration:underline">non</span> appartengono al linguaggio Gambas, bensì a librerie esterne di funzioni. Tali funzioni esterne possono essere richiamate e gestite da Gambas mediante la parola [[Extern:_richiamare_funzioni_esterne_a_Gambas|Extern]].
 
* Funzioni esterne. Tali funzioni <SPAN Style="text-decoration:underline">non</span> appartengono al linguaggio Gambas, bensì a librerie esterne di funzioni. Tali funzioni esterne possono essere richiamate e gestite da Gambas mediante la parola [[Extern:_richiamare_funzioni_esterne_a_Gambas|Extern]].
  
[6] Anche se non è una regola rigida che possa dare errore, in Gambas una Funzione ''restituisce'' sempre un valore alla Funzione ''chiamante''; pertanto si preferisce definirla con la parola chiave ''Function'' (preceduta dalla parola chiave ''Public'' o ''Private'' a seconda ovviamente delle necessità), rispetto ad una routine che ''non'' restituisce alcun valore, e che - in tal caso - verrà definita con la parola chiave ''Sub'' o ''Procedure'' (preceduta dalla parola chiave ''Public'' o ''Private'' a seconda ovviamente delle necessità),.
+
[6] Riguardo alla differenza fra le parole-chiavi "Sub", Procedure" e "Function" si veda la seguente pagina della wiki: [[Differenza fra Sub, Procedure e Function]].
<BR>Ricapitolando:
 
<BR>- se la subroutine chiamata restituisce un valore alla Funzione ''chiamante'', allora la subroutine chiamata sarà considerata una ''Funzione'' in senso stretto, e verrà dichiarata formalmente con la parola chiave ''Function'':
 
Public/Private '''Function''' Nome_Funzione(parametro As tipo_valore, ......) As tipo_valore
 
 
  .....
 
  .....
 
 
 
  Return valore
 
 
 
End
 
 
 
- se invece la subroutine chiamata <SPAN Style="text-decoration:underline">non</span> restituisce un valore alla Funzione ''chiamante'', allora la subroutine chiamata sarà considerata una mera ''Procedura'', e si preferisce dichiararla formalmente con la parola chiave ''Procedure'' o con ''Sub'':
 
Public/Private '''Procedure''' Nome_Procedura(parametro As tipo_valore, ......)
 
 
  .....
 
  .....
 
 
 
End
 
  
 
[7] In Gambas elementi complessi come gli Oggetti vengono sempre passati come Riferimento, ovvero l'indirizzo di memoria in cui si trovano. Riguardo invece alle normali variabili di tipi base (Byte, Short, Integer/String/Long ecc.) queste non sono Oggetti ma "valori" ben precisi, che vengono passati come "Valore", e non come locazione di memoria. Questa differenza implica che, per quanto riguarda gli Oggetti, ogni modifica al suo contenuto viene mantenuta, mentre per le variabili, dato che ne viene passata una copia del valore, queste vengono perse all'uscita della stessa funzione che le gestisce.
 
[7] In Gambas elementi complessi come gli Oggetti vengono sempre passati come Riferimento, ovvero l'indirizzo di memoria in cui si trovano. Riguardo invece alle normali variabili di tipi base (Byte, Short, Integer/String/Long ecc.) queste non sono Oggetti ma "valori" ben precisi, che vengono passati come "Valore", e non come locazione di memoria. Questa differenza implica che, per quanto riguarda gli Oggetti, ogni modifica al suo contenuto viene mantenuta, mentre per le variabili, dato che ne viene passata una copia del valore, queste vengono perse all'uscita della stessa funzione che le gestisce.
 
<BR>Il concetto di parametro passato "per Riferimento" (ByRif) in Gambas, fa sì che la funzione prende in ingresso l'indirizzo di memoria in cui è depositato il valore, e non ne crea una copia. Ciò consente, come per gli Oggetti, di ritrovarsi la variabile di base modificata anche dopo l'uscita dalla funzione.  
 
<BR>Il concetto di parametro passato "per Riferimento" (ByRif) in Gambas, fa sì che la funzione prende in ingresso l'indirizzo di memoria in cui è depositato il valore, e non ne crea una copia. Ciò consente, come per gli Oggetti, di ritrovarsi la variabile di base modificata anche dopo l'uscita dalla funzione.  
  
[8] Al riguardo vedere anche la seguente pagina della WIKI: http://www.gambas-it.org/wiki/index.php?title=Passaggio_di_un_argomento_per_%27indirizzo%27_ad_una_Funzione
+
[8] Al riguardo vedere anche la seguente pagina della WIKI: [[Passaggio di un argomento per 'indirizzo' ad una Funzione]]

Versione attuale delle 16:03, 21 giu 2024

Una Funzione [note: 1 2 3 4 5] è una routine, chiamata da una routine principale, alla quale è delegato il compito di svolgere una serie di operazioni, e delle quali essa restituisce il risultato alla routine principale chiamante.

La Funzione è l'operazione attinente ad una fase del processo del programma.

Dichiarazione di una Funzione

Va precisato che in Gambas non è prevista nel codice del programma la dichiarazione di una Funzione.

Definizione di una Funzione

La "definizione" della Funzione stabilisce:

  • il nome (Identificatore ) della Funzione medesima;
  • i valori in entrata, passati dalla omonima Funzione chiamante, definiti «parametri formali »;
  • il blocco delle istruzioni che compiono le operazioni necessarie per ottenere il risultato previsto dalla Funzione;
  • il valore di ritorno ottenuto dalla predette istruzioni operative.

Gli eventuali "parametri formali " di una Funzione sono posti all'interno di due parentesi tonde, nelle quali sono specificati di ciascun parametro l'identificatore e il tipo di dato.
In Gambas ogni Identificatore di Funzione è consentito per una sola Funzione. Pertanto non possono esssere definite due o più Funzioni aventi il medesimo nome (identificatore).
Il Blocco delle istruzionidi una Funzione rappresenta il valore permanente associato a una Funzione. In esso può essere inserita qualsiasi istruzione, compresa una chiamata di Funzione.

La Funzione, creata dal programmatore, in Gambas è sostanzialmente definita con il seguente prototipo:

[Public/Private] Function Nome_Identificativo( [Parametro As tipo_di_dato, ...idem...] ) As Tipo_di_dato_ritornato
  
 eventuali_dichiarazioni_di_tipi_di_variabili
  
 istruzioni
  
 Return valore_da_ritornare
  
End

La parola chiave FUNCTION, che specifica e definisce una Funzione chiamata, può essere preceduta dalla parola chiave Public o Private a seconda delle necessità di visibilità della Funzione medesima.

Una Funzione, per essere utilizzata dal processo del programma, deve essere invocata, chiamata da una specifica Funzione chiamante. Tale Funzione chiamante deve avere un nome identificativo identico a quello della Funzione chiamata.

Inoltre, se è previsto che la Funzione chiamante passi alla Funzione chiamata uno o più valori, affinché essi vengano processati dalle istruzioni contenute dalla Funzione chiamata, detti valori pasati devono essere del tipo identico a quello dichiarato nella Funzione chiamata. In tal senso i valori, passati dalla Funzione chiamante sono definiti «Parametri attuali » o «argomenti », mentre i valori dichiarati - e quindi poi ricevuti - dalla Funzione chiamata (ove la Funzione è definita) sono nominati «Parametri formali ».

I Parametri formali enunciati nella definizione di una Funzione, possono essere considerati come parametri potenziali, nel senso che essi rappresentano il tipo di dato che la Funzione può ricevere.
I Parametri attuali o Argomenti sono appunto i dati effettivamente passati alla Funzione "chiamata" attraverso la Funzione "chiamante" nello stretto rispetto dei tipi di dati attesi dalla definizione della Funzione medesima.

La Funzione chiamata ritorna sempre un valore, che è il risultato delle operazioni svolte dalle istruzioni presenti nella Funzione. [Nota 6]
Anche il dato ritornato dall'istruzione Return può essere in sostanza considerato un parametro potenziale, sebbene in questo caso in "uscita" dalla Funzione.

Mostriamo di seguito un semplice esempio pratico con la modalità più comune di ritorno di valore:

Public Sub Main()

 Dim i, rit As Integer
 
 i = 10
  
' La seguente Funzione "chiamante" invoca la Funzione "chiamata" e le passa un valore come "argomento", affinché sia processato, e dalla quale riceverà un valore come risultato di quel processo:
 rit = Calcolare(i)
  
 Print "Valore ritornato: "; i
  
End


' La seguente Funzione "chiamata" riceve un valore, come "parametro" dalla Funzione "chiamante".
' Quindi lo elabora con le istruzioni da essa contenute, e lo restituisce alla Funzione "chiamante":
Private Function Calcolare(valore As Integer) As Integer
 
 Dim n, r As Integer
 
 n = 100
  
 r = valore * n
  
 Return r
  
End


Passaggio dei dati ad una Funzione

Nel paragrafo precedente abbiamo visto con la parola Return la modalità più frequente e più semplice per ritornare in Gambas un dato da una Funzione. Ma non è la sola modalità.

In Gambas la routine principale chiamante può passare attraverso i suoi argomenti uno o più valori alla Funzione chiamata. Il passaggio degli argomenti ad una Funzione può essere di tre tipi: [Nota 7]

  • per Valore;
  • per Indirizzo;
  • per Riferimento.


Passaggio per Valore

Il passaggio per Valore è senz'altro la modalità più frequente di passare dei dati ad una Funzione chiamata.

Nel passaggio per Valore viene passato un valore o sotto forma di dato effettivo (ad esempio direttamente un dato numerico) oppure indirettamente mediante una variabile (ad esempio di tipo Byte, Short, Integer, etc.) che contiene e dunque fornisce un valore.

Con il passaggio per Valore viene effettuata una copia della variabile passata alla Funzione chiamata come argomento della routine principale chiamante. Inoltre, le modifiche alla variabile del parametro passato, effettuate nella Funzione chiamata, restano confinate nell'ambito locale di detta Funzione secondaria. Ciò significa che la variabile, passata come parametro dalla routine chiamante a quella chiamata, non vede modificarsi il suo valore, nonostante la sua copia abbia subito una modifica del proprio valore a seguito di una o più operazioni nella Funzione secondaria chiamata. La viariabile presente nella routine principale chiamante resta intatta, immodificata, qualunque cosa avvenga alla sua copia nella Funzione chiamata.
Se, dunque, non vi fosse ritorno di valore della varibile-copia, ora con valore modificato, alla routine principale chiamante, non sarebbe possibile utilizzare nella predetta routine chiamante le modifiche apportate dalle operazioni, alle quali la Funzione secondaria chiamata è stata preposta.

Mostriamo un semplice esempio:

Public Sub Main() ' Routine principale

 Dim a, b, risultato_di_ritorno As Integer

 a = 2
 b = 3

' Chiama la Funzione, e le passa i due valori, affinché li elabori.
' Alla fine la Funzione restituirà il risultato che riempirà la variabile integer "risultato_di_ritorno":
 risultato_di_ritorno = funzione_chiamata(a, b)
 
' Mostriamo il risultato in console:
 Print "Risultato di ritorno dalla funzione = "; risultato_di_ritorno

End


' La funzione secondaria "Funzione_Chiamata" contiene il proprio nome ed i parametri come variabili dei valori passati dalla routine chiamante, e non prevede l'aggiunta della parola chiave "Sub".
' Essa, poiché restituisce - in questo nostro esempio - un valore Integer, termina la propria dichiarazione con "As Integer" .
Private Function Funzione_Chiamata(aF As Integer, bF As Integer) As Integer

 Dim somma As Integer

' Non è necessario dichiarare le due variabili, poiché lo si è già fatto nei parametri della funzione:
  somma = aF + bF

' Viene restituito il risultato alla routine chiamante:
  Return somma
 
End

In console avremo coerentemente:
Risultato di ritorno dalla funzione = 5


...e se la Funzione deve restituire due o più dati ?

Se la Funzione deve restituire più di un dato non è possibile utilizzare l'istruzione Return con una variabile ordinaria, giacché essa restituisce un solo dato.

Per ottenere da una medesima Funzione due o più risultati (quindi senza dover utilizzare una variabile globale), possiamo utilizzare due modalità:

  • uso di una variabile vettoriale o di una Struttura;
  • il passaggio per indirizzo (vedi paragrafo successivo).

Uso di un vettore come ritorno di una Funzione

Mostriamo un esempio di una Funzione che ritorna per "valore" un duplice risultato mediante una variabile vettoriale:

Public Sub Main()

 Dim a, b As Integer
 Dim risultato_di_ritorno As Integer[]
 
 a = 2
 b = 3

' Chiama la Funzione, e le passa i due valori, affinché li elabori. Alla fine la Funzione restituirà il risultato che riempirà la variabile vettoriale integer[] chiamata "risultato_di_ritorno":
 risultato_di_ritorno = Funzione_Chiamata(a, b)

' Mostriamo il primo risultato (la somma) in console:
 Print "Risultato (somma) di ritorno dalla funzione = "; risultato_di_ritorno[0]

' Mostriamo il secondo risultato (la differenza) in console:
 Print "Risultato (differenza) di ritorno dalla funzione = "; risultato_di_ritorno[1]

End


' La routine Funzione, poiché restituisce - per "Valore " - un valore vettore Integer[], termina la propria dichiarazione con: As Integer[].
Public Function Funzione_Chiamata(aF As Integer, bF As Integer) As Integer[]

 Dim somma, differenza As Integer
 Dim doppiorisultato As New Integer[]

 somma = aF + bF
 differenza = bF - aF

' Nel primo campo dell'array inseriamo il valore contenuto dalla variabile Integer "somma":
 doppiorisultato.Add(somma)

' Nel secondo campo dell'array inseriamo il valore contenuto dalla variabile Integer "differenza":
 doppiorisultato.Add(differenza)

' Dunque ora la variabile Integer[] "doppiorisultato" contiene due valori.
' Tale duplice contenuto di questa variabile Integer[] viene restituito alla routine principale chiamante:
 Return doppiorisultato

End

In console avremo coerentemente:
Risultato (somma) di ritorno dalla funzione = 5
Risultato (differenza) di ritorno dalla funzione = 1


Passaggio per Indirizzo

Il passaggio per Indirizzo prevede che la routine principale chiamante passi come propri argomenti alla Funzione chiamata gli indirizzi di memoria delle variabili della routine chiamante contenenti i valori che dovranno essere gestiti dalle istruzioni della Funzione chiamata. [Nota 8]

Nel passaggio per indirizzo viene - appunto - passato l'indirizzo di memoria ove è memorizzato un valore oppure un Oggetto.

Il passaggio per Indirizzo di un argomento può avvenire mediante:

  • i Vettori;
  • la variabile di tipo Puntatore;
  • le Strutture;
  • le variabili identificatrici di un Oggetto, quale istanza di una Classe.

Ciò in quanto le rispettive variabili contengono gli indirizzi alle aree di memoria da esse puntate ove sono memorizzati i vari dati.
Quando si deve passare l'indirizzo di memoria di una variabile, diversa da un Vettore e da una Struttura, si userà la funzione VarPtr( ), altrimenti si passerà un Puntatore ad un'area di memoria opportunamente allocata con al funzione Alloc( ).

La particolarità del passaggio degli argomenti per indirizzo è che tale modalità di passaggio ci consente di eliminare l'istruzione Return, e di ritornare, così, il valore dalla Funzione chiamata alla routine principale chiamante attraverso i parametri medesimi della Funzione. Inoltre, esso non determina la creazione di una copia della variabile passata (come invece avviene per il passaggio per valore).
Avere un riferimento all'oggetto è molto utile in fase di passaggio tramite parametri tra un Metodo e l'altro. La modifica dell'oggetto fa sì che venga mantenuta in uscita dal Metodo, eliminando così l'obbligo del ritorno di un valore.

E' appena il caso di ricordare che il passaggio di valori "per Indirizzo" a una sotto-procedura/funzione, non crea una copia dell'Oggetto, o comunque del tipo, passato, come avviene invece nel passaggio "per Valore", ove si va ad occupare un'altra area di memoria (per generare la copia) di dimensioni pari a quella occupata dall'Oggetto (o dal tipo di valore) passato.
Va da sé che con il passaggio "per Valore", avendo due copie uguali, avremo due indirizzi di memoria che si riferiscono ovviamente a due aree di memoria riservate automaticamente di uguale dimensione, ...e quindi un consumo doppio delle risorse (ossia della memoria necessaria per il passaggio dei dati).
Il passaggio "per Indirizzo" fa in modo che la modifica avvenga direttamente all'indirizzo di memoria dell'Oggetto (o del tipo di valore) passato evitando così la creazione di una copia e l'occupazione di altra memoria per il medesimo dato da passare.

Semplici esempi pratici

Mostriamo un esempio pratico con un Vettore:

Public Sub Main()
 
 Dim vett As New Integer[4]
 Dim i As Integer
 
 Funzione(vett)
  
 For Each i In vett
   Print i
 Next
  
End


Private Function Funzione(ii As Integer[])
 
 Dim c As Integer
 
 For c = 0 To ii.Max
   ii[c] = c + 1000
 Next
 
End

Ora un esempio con una Struttura:

Public Struct STRUTTURA
  b As Byte
  s As Short
  i As Integer
  l As Long
End Struct


Public Sub Main()
 
 Dim sr As New STRUTTURA
 
 Funzione(sr)
  
 With sr
   Print .b
   Print .s
   Print .i
   Print .l
 End With
  
End


Private Function Funzione(tr As STRUTTURA)
 
 With tr
   .b = 100
   .s = 1000
   .i = 100000
   .l = 10000000
 End With
 
End

Quindi un paio di esempi nei quali la funzione passa l'indirizzo di memoria di una variabile dichiarata. Per scrivere nella variabile, ricevuta come parametro di tipo Puntatore della Funzione chiamata, il risultato finale delle operazioni compiute in tale Funzione, bisognerà ovviamente utilizzare i Memory Stream unitamente alla funzione Write.

Mostriamo un esempio, nel quale la funzione passa l'indirizzo di memoria di una variabile dichiarata di tipo Intero Lungo:

Public Sub Main()
 
 Dim num As Long
 
 Funzione(VarPtr(num))
   
 Print num
  
End
 

Private Function Funzione(p As Pointer)
 
 Dim st As Stream
 
 st = Memory p For Write
 Write #st, 1234567890 As Long
 st.Close
 
End

Dello stesso tipo appena visto, il seguente esempio, ove avviene lo scambio di valori fra due variabili (swapping):

Public Sub Main()
 
 Dim i1, i2 As Integer
 
 i1 = 1000
 i2 = 2000
   
 Scambio(VarPtr(i1), VarPtr(i2))
   
 Print i1, i2
  
End


Private Function Scambio(x As Pointer, y As Pointer)
 
 Dim z As Integer
 Dim st As Stream
    
 z = Int@(x)
   
 st = Memory x For Write
 Write #st, Int@(y) As Integer
 st.Close
   
 st = Memory y For Write
 Write #st, z As Integer
 st.Close
  
End

Nei seguenti due esempi, invece, sarà passata una variabile di tipo Puntatore che punta ad un'area di memoria appositamente riservata.
In questo esempio l'area di memoria conterrà valori numerici generici:

Public Sub Main()
 
 Dim ptr As Pointer
 Dim c As Integer
 
 ptr = Alloc(SizeOf(gb.Byte), 8)
 
 Funzione(ptr)
   
 For c = 0 To 7
   Print Byte@(ptr + c)
 Next

' Libera la memoria precedentemente allocata, affinché possa essere utiliata dal sistema:
 Free(ptr)
' Assegna alla variabile "Puntatore" il valore di default, affinché non punti a un indirizzo di memoria rilevante:
 ptr = 0

End


Private Function Funzione(p As Pointer)
 
 Dim st As Stream
 Dim b As Byte
    
 st = Memory p For Write
 For b = 1 To 8
   Write #st, b * 10 As Byte
 Next
 st.Close
 
End

In quest'altro esempio sarà passata un'area di memoria contenente i valori prettamente attinenti a caratteri stringa:

Public Sub Main()

 Dim p As Pointer
 
 p = Alloc("abcde")
  
 Funzione(p)
   
 Print String@(p)

' Libera la memoria precedentemente allocata, affinché possa essere utiliata dal sistema:
 Free(p)
' Assegna alla variabile "Puntatore" il valore di default, affinché non punti a un indirizzo rilevante di memoria:
 p = 0

End


Private Function Funzione(po As Pointer)
 
 Dim st As Stream
   
 st = Memory po For Write
  
 Write #st, 70 As Byte
  
 st.Close
 
End


Ritorno di più dati

Come già accennato, la modalità del passaggio per Indirizzo ci consente di ritornare alla routine chiamante anche più dati.

Mostriamo un esempio pratico, nel quale vengono ritornati due dati attraverso i parametri della Funzione chiamata e di quella chiamante:

Public Sub Main()

 Dim dividendo, divisore As Integer
 Dim p1, p2 As Pointer

 Print "Scrivere i valori del dividendo e del divisore."
 Input dividendo
 Input divisore

 p1 = VarPtr(dividendo)
 p2 = VarPtr(divisore)

 Funzione_Chiamata(p1, p2)

 Print "Quoziente: "; Int@(p1)
 Print "Resto: "; Int@(p2)

End


Private Function division(divid As Pointer, divis As Pointer)

 Dim i1, i2, ris As Integer
 Dim st As Stream
 
 i1 = Int@(divid)
 i2 = Int@(divis)
 ris = i1 / i2

 st = Memory divid For Write
 Write #st, ris As Integer
 st.Close
   
 ris = i1 Mod i2

 st = Memory divis For Write
 Write #st, ris As Integer
 st.Close

End


Ritorno di dati per "Indirizzo" senza utilizzo come argomento di un esplicito Puntatore

Abbiamo visto nel paragrafo appena precedente che qualora il tipo di argomenti sia una Struttura oppure un vettore, non v'è necessità che i parametri, passati alla Funzione chiamata, siano di tipo Puntatore, giacché essi stessi puntano all'area di memoria degli Oggetti che rappresentano.

Ripetiamo gli esempi con una Struttura:

Public Struct STRUTTURA
  b As Byte
  s As Short
  i As Integer
End Struct


Public Sub Main()

 Dim st As New STRUTTURA
 
 With st
   .b = 99
   .s = 9999
   .i = 999999
 End With

 Funzione_Chiamata(st)
   
 With st
   Print .b
   Print .s
   Print .i
 End With

End


Private Function Funzione_Chiamata(n As STRUTTURA)
 
 With n
   .b += 99
   .s += 9999
   .i += 999999
 End With

End

e con un Vettore:

Public Sub Main()

 Dim ss As String[] = ["a", "b", "c"]
  
 Print ss.Count
   
 Prova(ss)
   
 Print ss.Count

End


Private Function Prova(vett As String[])

 vett.Remove(1)
  
End


Passaggio per Riferimento

Il passaggio per Riferimento in Gambas prevede sia nella Funzione chiamante sia nella Funzione chiamata l'uso della parola chiave ByRef prima dell'argomento da passare.

Questa modalità è una risorsa specifica e all'uopo dedicata di Gambas per passare per indirizzo variabili che non siano già di per sé comunque dei Puntatori. Infatti essa è nella sostanza identica a quella per "Indirizzo ": non necessita dell'uso dell'istruzione Return al termine della Funzione chiamata.
Come già detto nel paragrafo relativo al passaggio di argomenti per Indirizzo, avere un riferimento all'oggetto è molto utile in fase di passaggio tramite parametri tra un Metodo e l'altro. La modifica dell'oggetto fa sì che venga mantenuta in uscita dal Metodo, eliminando così l'obbligo del ritorno di un valore.

Mostriamo un esempio:

Public Sub Main()

 Dim a, b As Integer

 a = 2
 b = 3

 Funzione_Chiamata(ByRef a, b)

 Print "Risultato di ritorno dalla funzione = "; a

End


Private Function Funzione_Chiamata(ByRef aRif As Integer, bI As Integer)

 Dim somma As Integer
 
' Si effettua l'operazione fra i due argomenti, ed il risultato viene restituito attraverso il parametro individuato con "ByRef":
 aRif = aRif * bI

End


Ritorno di più dati

Anche con il passaggio per Riferimento mediante la parola chiave "ByRef " è possibile ritornare alla funzione chiamante due o più dati. Per fare ciò si dovrà porre la parola chiave ByRef su due o più argomenti da passare delle Funzioni chiamante e chiamata.


Scrivere ed invocare una Funzione in un Modulo

La scrittura e la successiva invocazione di una Funzione in un Modulo segue la procedura normale.

Facciamo un semplissimo esempio.

Nella Classe principale avremo il seguente codice:

Public Sub Form_Open()  
 
 Dim b As Byte  
  
' Invochiamo la funzione nel Modulo e le passiamo un valore di tipo Byte (in questo esempio: 6 ).
' Essa, a sua volta, ci passerà un valore che inseriremo nella variabile "b":
 b = Module1.funzioneNelModulo(6)
 
 Print b
 
End

Nel Modulo avremo:

Public Function funzioneNelModulo(a As Byte) As Byte  ' Riceve dalla routine chiamante un valore di tipo "Byte", ed un valore di tipo "Byte" a sua volta restituirà  
  
 Dim b As Byte  
  
 b = 2  
  
' La Funzione effettua l'operazione per la quale è stata concepita:
 b = b * a  
  
' Restituisce, quindi, alla routine chiamante, presente nella Classe principale, il risultato dell'operazione:
 Return b
  
End


Note

[1] «La "funzione" di una cosa è ciò che la sola cosa può compiere.» (Platone, La Repubblica)

[2] La Funzione è un complesso di operazioni coordinate, tale da configurarsi in sé come una norma.

[3] La Funzione " offre un metodo conveniente per racchiudere una parte di programma in grado di eseguire un compito specifico, in modo che sia riutilizzabile senza preoccuparsi della sua implementazione. " (Kernighan B. W. - Ritchie D. M., Il linguaggio C - seconda edizione, Pearson edizioni)

[4] Si rinvia anche a Wikipedia per una definizione più ampia della Funzione.

[5] Possiamo distinguere quattro tipi di Funzioni:

  • native ed autonome. Si tratta di quelle Funzione che sussistono di per sé all'interno di Gambas, avendo così una dignità propria (ad esempio: "Alloc()", "SizeOf()", "Max()" e così via).
  • metodi di Classi Gambas. Si tratta di quelle Funzioni di Gambas che non sono autonome, ma esistono in quanto risorse tipiche di una Classe. Tali Funzioni (Metodi) possono essere utilizzati solo se richiamate attraverso un Oggetto di una Classe. Esempi di tali Funzioni: "Object.SizeOf()", "Button1.Move()", "vettore.Push()", "Paint.DrawImage()" e così via.
  • Funzioni scritte dal programmatore (oggetto della presente pagina): sono appunto specifiche Funzioni, scritte dal programmatore, per assolvere ad un particolare compito che si esaurisce con l'applicazione, nella quale la Funzione è stata appositamente creata.
  • Funzioni esterne. Tali funzioni non appartengono al linguaggio Gambas, bensì a librerie esterne di funzioni. Tali funzioni esterne possono essere richiamate e gestite da Gambas mediante la parola Extern.

[6] Riguardo alla differenza fra le parole-chiavi "Sub", Procedure" e "Function" si veda la seguente pagina della wiki: Differenza fra Sub, Procedure e Function.

[7] In Gambas elementi complessi come gli Oggetti vengono sempre passati come Riferimento, ovvero l'indirizzo di memoria in cui si trovano. Riguardo invece alle normali variabili di tipi base (Byte, Short, Integer/String/Long ecc.) queste non sono Oggetti ma "valori" ben precisi, che vengono passati come "Valore", e non come locazione di memoria. Questa differenza implica che, per quanto riguarda gli Oggetti, ogni modifica al suo contenuto viene mantenuta, mentre per le variabili, dato che ne viene passata una copia del valore, queste vengono perse all'uscita della stessa funzione che le gestisce.
Il concetto di parametro passato "per Riferimento" (ByRif) in Gambas, fa sì che la funzione prende in ingresso l'indirizzo di memoria in cui è depositato il valore, e non ne crea una copia. Ciò consente, come per gli Oggetti, di ritrovarsi la variabile di base modificata anche dopo l'uscita dalla funzione.

[8] Al riguardo vedere anche la seguente pagina della WIKI: Passaggio di un argomento per 'indirizzo' ad una Funzione