Falcon - il linguaggio



Le classi - 1            
 
Questo è, ovviamente, uno degli argomenti principe relativamente un linguaggio che si vuole supporti il protocollo a oggetti. Non starò qui a parlare dell'importanza delle classi, cosa su cui è facilissimo trovare informazioni dettagliate. In Falcon le classi, come in moltissimi altri linguaggi, sono una sorta di contenitore di valori (proprietà) e funzioni per gestire questi valori (metodi). Formalmente sono definite sulla base di questo schema:

class nomeclasse [(lista dei parametri)] [from x1 [, x2,....,xn]]
   [blocco statico]
   [dichiarazione delle proprietà]
   [blocco di inizializzazione]
   [lista dei metodi]
end

class è la keyword necessaria, così come end è il delimitatore di chiusura obbligatorio. Tutto quanto sta tra parentesi quadre è opzionale, la eventuale lista dei parametri è all'interno di una coppia di parentesi tonde. La keyword from introduce gli elementi da cui la classe corrente eredita. Un esempio minimale e ovviamente del tutto inutile è il seguente:

  Esempio 11.1
1
2
3
4
class test
end

> "classe ok"

Bene, vediamo ora di implementare un po' le cose. Sempre tenendoci la nostra classe test inseriamo in essa due valori, due proprietà:

classe test
x0 = 1
s1 = 2
end

La definizione come si vede è molto semplice, in questo formato di base. Una classe in se stessa è un po' come un nuovo tipo creato custom da parte del programmatore, uno schema di base, un prototipo, possiamo immaginarlo in tanti modi. Questo tipo può essere condiviso tra varie entità ciascuna indipendente dalle altre e ciascuna con un proprio comportamento peculiare nel corso di vita del programma, piuttosto che essere usato in modo monolitico. Ricordando comunque che in Falcon le classi sono considerate "callable items" e quindi sono richiamabili direttamente. D'altronde le classi vengono create come tipi customizzati ed ecco che il processo di istanziazione, quindi una sorta di creazione di variabili indipendenti basati sul nuovo tipo, risulta fondamentale. In Falcon abbiamo due strade maestre: la prima è quella di chiamare la classe come fosse una funzione. Vediamo l'esempio:

  Esempio 11.2
1
2
3
4
5
6
7
class test (x, y)
z = x
t = y
end

t01 = test(3, 4)
> t01.z + t01.t

La riga 6 è quella critica: essa crea una istanza della classe test passando i valori 3 e 4 ai parametri richiesti dalla stessa.

Il secondo metodo di istanziazione è quello di creare un oggetto a partire dalla classe:

  Esempio 11.3
1
2
3
4
5
6
7
8
class test (x, y)
z = x
t = y
end

object t01 from test(3, 4)
end
> t01.z + t01.t

Questo secondo metodo, che come èevidente fa uso della keyword from,  permette di inizializzare eventuali elementi interni e anche di estendere la classe. Estendere una classe è, in linea di principio, semplice,  si può modificare il codice dell'esempio 11.3 come segue, lasciando inalterata la classe test:

object t01 from test(3, 4)
s = 5
end
> t01.z + t01.t + t01.s


Oltre che valori le classi possono contenere anche delle funzioni, introdotte tramite la consueta keyword function.

  Esempio 11.4
1
2
3
4
5
6
7
8
9
10
11
12
13
class test (x, y)
  z = x
  t = y
  function saluto()
    > "Sono la classe test"
  end
end

object t01 from test(3, 4)
s = 5
end
> t01.z + t01.t + t01.s
t01.saluto()

In rosso le righe che definiscono la funzione all'interno della classe test e il suo uso da parte della variabile creata ad hoc.

Le classi possono usare anche le variabili definite internamente ad esse ma è necessario in tal caso far uso della keyword self. Quest'ultima equivale al this di C# e Java, per fare un esempio, senza di essa l'interprete manda un messaggio d'errore. Per esempio:

  Esempio 11.5
1
2
3
4
5
6
7
8
9
10
class test (x, y)
z = x
t = y
function somma()
> self.z + self.t
end
end

t01 = test(4, 6)
t01.somma()

Come detto se togliamo il "self" l'interprete dichiara che la variabile è indefinita.

Nella definizione formale delle classi troviamo anche un blocco di inizializzazione. Esso risulta importante quando è necessario lavorare un po' più approfonditamente per inizializzare completamente la nostra classe. Tramite questo blocco è possibile compiere alcune operazioni in fase di creazione della classe. Un esempio banale è il seguente:

  Esempio 11.6
1
2
3
4
5
6
7
8
9
10
class test (x, y)
  z = x
  t = y

  init
    > "il primo parametro vale: ", self.z
  end
end

t01 = test(3,4)

Ovviamente si possono fare cose molto più complicate.

Per ora, in questa fase introduttiva, ci fermiamo qui.