Metodi nascosti
_new(), _free()
In Gambas, per tutti gli oggetti base, sono presenti alcuni metodi, che di norma non vengono presi in considerazione e che, in effetti, non vengono neppure dichiarati durante la costruzione di un oggetto. Dato che ogni oggetto deriva in ogni caso dalla classe base Object di Gambas, anche queste proprietà nascoste vengono definite nelle nuove sotto classi. L'utilità di questi metodi è enorme, dato che tramite queste è possibile modificare le proprietà di base dell'oggetto stesso, passare parametri, definire condizioni di funzionamento, chiudere file aperti, rilasciare risorse, ecc. Questa particolarità è inclusa sia nelle classi dinamiche (es. ListBox, Menu, ecc.), sia le classi statiche come, ad esempio, le Form.
In genere, nei linguaggi odierni, questo tipo di implementazione, oltre che far parte del concetto stesso di oggetto (o classe), ha una funzione e una visibilità più evidente, come ad esempio il C++, Java e Il Python (per citarne alcuni). Nella maggioranza dei casi, questi metodi diventano quasi indispensabili per il funzionamento di un'applicazione.
Per ritornare a Gambas, parliamo dei due metodi che, a mio avviso, credo siano le funzioni più utili: _new() e _free(). [Nota 1]
_new() - Il Costruttore
Il Costruttore "_New()" è un Metodo nascosto che viene eseguito al momento della costruzione dell'Oggetto (come fosse un Evento speciale della Classe a cui appartiene).
Esso può ricevere argomenti passati all'atto della creazione dell'Oggetto della Classe specifica mediante la parola-chiave "New". [Nota 2]
Per fare un esempio, la classe Form non accetta di norma alcun parametro, ma vediamo come è possibile modificare questa impostazione in modo tale, ad esempio, da potergli passare un array di stringhe:
Creiamo una Form, e apriamo l'editor di testo per modificare il codice della Form, e scriviamo le istruzioni seguenti:
PRIVATE $arr AS String[] ... ... PUBLIC SUB _new( arr AS String[] ) ... $arr = arr ... END
Cosa abbiamo ottenuto? Bè, nulla di particolare... abbiamo solo detto a Gambas che la Form ora accetta un parametro, di tipo String[] !
Questa possibilità è solo permessa attraverso questo metodo nascosto, altrimenti la cosa non sarebbe stata fattibile, se non attraverso metodi poco ortodossi (come, ad esempio, delle variabili globali), e questo permette di condizionare enormemente un oggetto. Se, come da esempio, salviamo il parametro in una variabile privata della classe (nell'esempio: $arr), possiamo poi gestire i suoi dati all'interno della classe, modificarli e, magari restituirli alla chiusura della Form. Un'altra ottima caratteristica di questo metodo, è il fatto che il suddetto viene sempre e comunque invocato alla creazione della classe, prima di qualunque altro, per cui rende possibile condizionare totalmente la gestione della classe stessa; nessun evento e nessun'altra funzione sarà chiamata o attivata, se non dopo l'esecuzione del Metodo nascosto "_new()" (il Costruttore!). [Nota 2]
Non esistono limitazioni sulla posizione del metodo all'interno del codice, ma, se presente, verrà comunque invocato.
L'unica cosa da tener presente è che, data l'inerenza dalla classe base Object, e da eventuali altre, verranno chiamati prima i metodi _new() delle classi superiori, partendo da quella più in alto, fino ad arrivare alla nostra (come per l'esempio). Eventuali parametri, già previsti nelle classi superiori, verranno caricati prima di quelli della nostra classe. E' anche da ricordare che l'elenco dei parametri passati alla nostra classe deve comprendere anche quelli delle classi superiori, e il loro posizionamento deve seguire la logica: da destra verso sinistra, ovvero la prima che sarà letta e utilizzata è la prima a destra.
Come esempio, costruiamo una classe MyButton, derivata dalla classe base Button di Gambas.
Tramite l'IDE di Gambas, creiamo una classe MyButton, quindi apriamo l'editor per modificarne il codice:
INHERITS Button ... PUBLIC SUB _new( etichetta AS String ) 'passiamo l'etichetta che verrà impostata come testo del pulsante ... WITH ME .Text = etichetta END WITH ... END
A questo punto, per utilizzare l'oggetto MyButton, è necessario il codice seguente:
PUBLIC SUB CreaMyButton() ... DIM MyBtn AS MyButton ... MyBtn = NEW MyButton("OK", hForm) ... END
Come è possibile capire dall'esempio, nella funzione "CreaMyButton()", viene definito un oggetto MyBtn di tipo MyButton (la nostra classe), e nella sua creazione vengono passati due parametri: la stringa "OK" e hForm. Il primo rappresenta l'etichetta da stampare sul pulsante, il secondo il riferimento all'oggetto contenitore (una Form). E' da notare la posizione dei due parametri, in cui nel primo posto viene passata l'etichetta, nel secondo il riferimento al contenitore; nella creazione della classe MyButton, come prima cosa viene creata la classe base Button, a cui verrà passato il riferimento alla Form (il secondo parametro), quindi verrà creata la classe derivata MyButton, a cui verrà passata l'etichetta che abbiamo definito come parametro nel metodo _new() (primo parametro).
Con questa logica è anche possibile definire parametri opzionali (OPTIONAL), magari con valori di default che verranno impostati se non presenti nella creazione dell'oggetto:
Esempio:
INHERITS Button ... PUBLIC SUB _new( OPTIONAL etichetta AS String = "OK" ) 'se non passata, l'etichetta sarà impostata a "OK" ... WITH ME .Text = etichetta END WITH ... END
_free() - Il Distruttore
Come esiste un Costruttore, credo a mio avviso debba esistere un Distruttore, a completamento del filo logico. In Effetti, come anche in altri linguaggi, questo "Distruttore" esiste, e in Gambas è assunto dal metodo "_free()".
Il metodo _free() ha il non semplice compito, almeno per quanto riguarda le operazioni a basso livello, di chiudere e rilasciare le risorse occupate e utilizzate dalla classe. In definitiva è un pulitore.
Il motore di Gambas ha una sua logica interna, che provvede automaticamente questo tipo di pulizia, che avviene normalmente per gli oggetti grafici, come ad esempio le Form e gli oggetti che racchiudono; ma, in alcuni casi, è necessario provvedere manualmente (inteso come codice) a liberare le risorse utilizzate. Questo è il caso, per esempio, di file aperti nella classe, di link a oggetti esterni alla classe, e così via. In questi casi, l'oggetto, non essendo in effetti consapevole degli elementi inseriti, al di fuori degli elementi previsti (esempio precedente, oggetti grafici), non prevede di gestirne la loro eliminazione, oltre al fatto che questa non è dipendente da situazioni o logiche previste nella loro impostazione di base. Per questi motivi, viene d'aiuto il metodo "_free()" che, come per "_new()", viene chiamato sempre e comunque, ma solo quando l'oggetto (o la classe) viene distrutta ed eliminata. Il metodo _free() non prevede parametri, nè li accetta, perchè la sua esecuzione è automatica e non può essere alterata da programma. Al suo interno, però, è possibile eseguire tutte le operazioni e il codice necessario alla corretta chiusura dell'oggetto. Credo sia inutile fare esempi, dato che comunque il codice non dipenderebbe dall'oggetto, ma sarebbe solo codice esterno ad esso; l'unico esempio è quello della dichiarazione del metodo stesso:
PUBLIC SUB _free() ... 'codice libero ... END
Il Distruttore è solo un Metodo nascosto che viene eseguito al momento della distruzione dell'Oggetto (come fosse un Evento speciale della Classe a cui appartiene) [Nota 3], e che di solito viene usato per liberare la memoria allocata dalla Classe (ma non la memoria della Classe !). Più in particolare il Distruttore non distrugge l'Oggetto (che viene cancellato dal Metodo ".Delete()", risorsa dell'Oggetto medesimo), ma la memoria allocata dai Metodi dell'Oggetto.
Note
[1] Vedere anche questa pagina della Wiki: Metodi New() e Free() degli oggetti
[2] In sostanza va tenuto presente che, se in una Classe è stato posto il Metodo nascosto _new( ):
- - - - all'atto della creazione di tale Classe - per mezzo della parola-chiave New - viene immediatamente invocato il predetto Metodo nascosto _new( );
- - - - è possibile passare mediante il Metodo nascosto _new( ) uno o più parametri alla nuova Classe immediatamente e contestualmente all'atto della sua creazione (effettuata con la parola-chiave New), come nell'esempio che segue:
- - - - se ad esempio nella Classe principale viene creata la Classe secondaria passando a quest'ultima un parametro di tipo Stringa:
Dim cl As Classe_secondaria cl = New Classe_secondaria("testo qualsiasi")
- - - - nella Classe secondaria il parametro verrà immediatamente recepito, prima di ogni altro metodo in essa eventualmente presente, appunto con il Metodo nascosto _new( ) e gestito di conseguenza come di consueto:
Public Sub _new(s As String) Print s End
[3] Facciamo ora un semplice esempio utilizzando due Classi: una Classe principale e una Classe secondaria.
La Classe principale (chiamata "FMain") avrà al suo interno il seguente codice:
Private cl1 As Class1 ' Questo Metodo nascosto della Classe principale viene sollevato all'atto della creazione della Classe principale medesima: Public Sub _new() Print "Classe Principale in creazione" ' In questo caso all'atto della creazione della Classe principale si provvede anche creare una Classe "secondaria" (chiamata "Class1") inviandole pure alcuni argomenti: cl1 = New Class1("Testo qualsiasi", 4444) End Public Sub Button1_Click() ' Si provvede a distruggere la Classe "secondaria" assegnando "Null" alla variabile che punta al suo Oggetto. (è opportuno ricordare che una Classe secondaria può essere distrutta soltanto dalla Classe che l'ha generata). cl1 = Null End
Mentre il codice nella Classe "secondaria" sarà il seguente:
' Questo Metodo nascosto della Classe "secondaria" viene sollevato all'atto della creazione della Classe "secondaria" medesima, e riceve gli argomenti passati con l'istruzione della creazione della Classe "secondaria" mediante la parola-chiave "New": Public Sub _new(s As String, i As Integer) Print "Classe secondaria in creazione" Print s, i End ' Questo Metodo nascosto della Classe "secondaria" viene sollevato all'atto della "distruzione" della Classe "secondaria" medesima: Public Sub _free() Print "Classe secondaria in distruzione" End
Insomma, i Metodi nascosti "_new()" e "_free()" non creano e non distruggono direttamente alcunché: essi, comportandosi come degli Eventi, sono sollevati rispettivamente all'atto della creazione e all'atto della distruzione della Classe di riferimento.