Falcon - il linguaggio



Funzioni e varie              
 
Vediamo qualche cosa di comodo, anche se non obbligatorio, nel linguaggio. Parliamo cioè dei codeblocks. Si tratta solo di una comodità sintattica per le funzioni anonime e quindi darò, per ora un solo esempio:

  Esempio 9.1
1
2
block = {a,b,c => a * b * c}(1,2,3)
>(block)

il formato generico è:

block = { [p1, p2..., pn] => espressione }

oppure

block = { [p1, p2..., pn] =>
istruzioni
...
}

dove p1, p2 ecc... sono parametri. I codeblocks che contengono più di una istruzione devono avere un valore di ritorno.
Vedremo più avanti altri esempi in cui saranno coinvolti i codeblocks.

Più particolari sono invece i cosiddetti callable arrays.
Essi hanno origine quando il primo elemento di un array è una funzione. In questo modo quando l'array viene richiamato, vedremo come, la funzione che si trova in prima posizione viene lanciata e gli altri elementi dell'array fungono da parametri. Altri parametri ancora possono essere passati alla funzione nelle modalità consuete. Vediamo un esempio di base:

  Esempio 9.2
1
2
ar1 = [printl, "Hello", "World"]
ar1()

Ecco un modo complicato per scrivere il nostro saluto internazionale. Oppure utilizzando una funzione creata da noi:

  Esempio 9.3
1
2
3
4
5
6
function mult(x)
  return x * x
end

ar1 = [mult, 5]
> ar1()

Passando un parametro ulteriore:

  Esempio 9.4
1
2
3
4
5
6
function mult(x, y)
return x * x * y
end

ar1 = [mult, 5]
> ar1(3)

Il risutato è 75 ovvero 5 * 5 * 3, quindi il primo parametro è quello all'interno dell'array, il secondo è quello passato alla riga 6.
Come descritto sul sito ufficiale, abbiamo un utililizzo interessante dei callable array ovvero come contenitori di valore pre memorizzati.

  Esempio 9.5
1
2
3
4
ar1 = [printl, "Hello "]
ar1("World!")
ar1("Raskrjal.Net!")
ar1("Universe!")

L'ultimo esempio lo costruiamo con un parametro al suo interno:

  Esempio 9.6
1
2
3
4
for i in [0:10]
icall = .[printl $i ": "]
icall( "Looping..." )
end

Tenete presente questa soluzione.

Sempre relativamente alle funzioni un'altra keyword utile è fself. Essa fornisce informazioni sulla funzione corrente e permette di stabilire chi è il chiamante di una funzione e in quale funzione stiamo lavorando. Un esempio dovrebbe bastare, detto che è applicabile anche in caso di codeblocks e nameless functions.

  Esempio 9.7
1
2
3
4
5
6
7
8
9
10
11
function somma(x, y)
printl(fself)
printl(fself.caller())
return x + y
end

function chiama()
> somma(2,3)
end

chiama()

Per chiudere, momentaneamente, il discorso sulle funzioni, parliamo ora dei cosiddetti parametri non posizionali. Si tratta di una interessante feature che permette di accedere ai parametri attraverso il loro nome invece che per via posizionale. Per fare questo in fase di chiamata della funzione bisogna ai parametri che si vogliono richiamare per nome il carattere | (pipe). Vediamo il consueto esempio:

Esempio 9.8
1
2
3
4
5
6
7
function somma( x1, x2, x3 )
> x1
> x2
> x3
end

somma(x1 | 3, x3 | 5)

L'output è:

3
Nil
5

e questo perchè alla riga 7 abbiamo attribuito un valore a x1 e x3 ma non ad x2.
Si possono anche mischiare parametri posizionali e non posizionali anche se la cosa potrebbe essere abbastanza bug-prone, a mio avviso se non si sta attenti. In questo caso infatti prima vengono applicati comunque i parametri posizionali poi quelli non posizionali. L'esempio che segue, banale modifica del precedente, ci mostra questo caso in azione e le conseguenze che potrebbero essere poco simpatiche, se non tenute in considerazione:

  Esempio 9.9
1
2
3
4
5
6
7
function somma( x1, x2, x3 )
> x1
> x2
> x3
end

somma(x1 | 3, 5, 3)

L'output è il seguente:

3
3
Nil


e questo è facilmente comprensibile in base a quanto abbiamo detto: vengono passati per primi i parametri posizionali, ovvero 5 e 3 rispettivamente a x1 e x2. Poi viene passato il parametro non posizionale che si impone su x1 sovrascrivendo il valore 5 precedentemente assegnato. Questo avviene in modo silente per cui, come detto e ridetto, bisogna fare attenzione.