Il linguaggio Fantom

Istruzioni               

Vediamo ora l'anatomia delle istruzioni in Fantom e qualcuna di quelle particolari del linguaggio.

Come descritto sul sito ufficiale, abbiamo tre modi per teminare una istruzione in Fantom:

-- tramite il classico newline (ovvero "andare a capo")
-- tramite il ; (punto e virgola) che ci riporta ai linguaggi c-like, usato soprattutto quando si mettono più istruzioni sulla stessa riga o in casi particolari che il compilatore segnala come ambiguità sintattiche
-- tramite la parentesi graffa di chiusura ( } ) che determina la fine di un blocco, al limite anche costituito da una sola espressione.

quindi, ad esempio

blocco
{
istruzione a
istruzione b
}

oppure

blocco
{
istruzione a; istruzione b
}


gli autori suggeriscono di utilizzare il primo sistema, tranne, appunto, quando il compilatore si fa sentire. Un'altra regoletta, direi banale ma obbligatoria, è che le parentesi per indicare parametri o altro, devono stare sulla stessa riga del loro riferimento.

Passiamo ora ad analizzare le classiche istruzioni di selezione e loop: per prima cosa abbiamo il caro vecchio:

if
------------

il cui costrutto si presenta così:

if (condizione booleana)
{
  istruzioni
}

oppure

if(condizione booleana)
{
  istruzioni
}
else
{
  istruzioni
}

e infine

if (condizione booleana)
{
  istruzioni
}
else if (condizione booleana)
{
  istruzioni
}
else
{
  istruzioni
}

L'esempio è banale:

  Esempio 3.1
1
2
3
4
5
6
7
8
9
10
11
class Test
{
  static Void main()
  {
    Env.cur.out.print("Inserisci un numero: ").flush
    x := (Env.cur.in.readLine).toInt
    if (x < 0) echo ("Il numero e' < 0")
    else if (x == 0) echo ("Il numero e' 0")
    else echo("Il numero e' > 0")
  }
}

Le righe 5 e 6 sono un po' complesse in apparenza ma non vale la pena preoccuparsi per ora. Basti sapere che la 5 è un'alternativa a echo con la differenza che non va a capo, la 6 gestisce l'input da console e il metodo toInt permette di avere in input una stringa ed in output un intero. Quindi x definito all'inizio della stessa riga 6 è un intero per inferenza. Il comando if non offre altre particolarità ne difficoltà laddove si abbia l'accortezza di scegliere con cura le casistiche che caratterizzeranno i vari rami. Da ricordare solo che il primo ramo che viene eseguito porta alla non presa in considerazione degli altri a questo successivi. Evidentemente per essere eseguito un ramo deve essere caratterizzato da un condizione booleana che assume il valore true.

while
---------------

Anche while è una classica istruzione standard che non presenta differenze sostanziali rispetto ad altri linguaggi:

while (condizione booleana)
{
istruzioni
}

con le graffe opzionali nel caso in vi sia una sola istruzione. La condizione booleana deve essere true affinche il while sia eseguito.

  Esempio 3.2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Test
{
  static Void main()
  {
    Env.cur.out.print("Inserisci un numero: ").flush
    x := (Env.cur.in.readLine).toInt
    y := 0
    while (y < x)
    {
      echo ("Incremento y")
      echo ("Differenza: "+ (x - y).toStr)
      y++
    }
  }
}

Fate solo attenzione a che non si verifichi un loop infinito dovuto alla mancata realizzazione del valore false della condizione booleana

for
---------------

Altra istruzione ben nota nel campo della programmazione. Formato:

for (inizializzazione; condizione; aggiornamento)
{
istruzioni
}


Le graffe come al solito sono opzionale se abbiamo una sola istruzione. Esempio:

  Esempio 3.3
1
2
3
4
5
6
7
8
9
10
11
class Test
{
  static Void main()
  {
    for (x := 0; x < 10; x++)
    {
      echo((x-10).toStr)
      echo("x: " + x.toStr)
    }
  }
}

Da notare che la variabile x è visibile solo all'intero del perimetro del ciclo for. Al di là della graffa presente alla riga 9 essa non è più visibile. Per poterla usare dentro e fuori bisogna definirla ad un livello più alto rispetto al for.

switch
---------------

Istruzione di selezione classica e alternativa in molti casi a if.

switch (elemento)
{
case (valore1):
  blocco 1
case(valore 2):
  blocco 2
....
case (valore n):
  blocco n
default:
  blocco
}


Si noti la presenza dei due punti al termine delle righe di definizione dei valori. Esempio:

  Esempio 3.4
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Test
{
  static Void main()
  {
    Env.cur.out.print("Inserisci un numero da 1 a 3: ").flush
    x := (Env.cur.in.readLine).toInt
    switch(x) {
    case 1:
      echo("Hai inserito il numero 1")
    case 2:
      echo("Hai inserito il numero 2")
    case 3:
      echo("Hai inserito il numero 3")
    default:
      echo("Hai inserito un numero errato")
      echo("Avevo detto 1, 2 o 3!") }
  }
}

Non ci sono grosse difficoltà di comprensione, ritengo. Vale solo la pena di fare alcune osservazioni:

** nel caso di vi siano più istruzioni non è necessario ricorrere alle graffe come è evidente alle righe 15 e 16
** diversamente da altri linguaggi non è necessario ricorrere al break per impedire il fall-thorugh, ovvero la caduta all'interno di più ramo, come avviene in C# e D ad esempio

Nonostante il fall through non sia permesso è tuttavia possibile riunisce più casi insieme. Si modifichi come segue l'esempio 3.4 dalla riga 8 alla 13:

case 1:
case 2:
case 3:
echo("Hai inserito un numero corretto")


In questo senso bisogna fare attenzione che dimenticare il corpo, l'implementazione di un branch comporta l'innesco di un fall-through.

Infine veniamo a due istruzioni anch'esse classiche che permettono di modificare il corso di esecuzioni di istruzioni iterate, quindi agiscono all'interno di for e while. Parliamo di break e continue. La prima istruzione blocca completamente l'esecuzione e salta fuori dal loop, la seconda salta solo l'iterazione corrente dal punto in cui si trova (quindi le istruzioni precedenti interne al loop vengono eseguite) e va a quella successiva.

  Esempio 3.5
1
2
3
4
5
6
7
8
9
10
11
class Test
{
  static Void main()
  {
    for (x := 0; x < 10; x++)
    {
      if (x == 5) continue
      echo(x.toStr)
    }
  }
}

L'output di questo piccolo programma è il seguente:

0
1
2
3
4
6
7
8
9

come si vede manca il numero 5 in quanto il programma, incontrando il continue è saltato all'iterazione successiva. Se a continue sostituite break il programma esce definitivamente dal loop e il programma prosegue oltre (in questo caso termina).