Differenze tra le versioni di "Metodi New() e Free() degli oggetti"

Da Gambas-it.org - Wikipedia.
Riga 22: Riga 22:
  
 
===Il metodo _New()===
 
===Il metodo _New()===
Nel metodo [https://gambaswiki.org/wiki/dev/api/cat/special/_new _New()] si possono definire e impostare i valori base e le proprietà dell'oggetto, e questo anche se è un Oggetto grafico (es. una ''Form'').
+
Nel metodo '''[https://gambaswiki.org/wiki/dev/api/cat/special/_new _New()]''' si possono definire e impostare i valori base e le proprietà dell'oggetto, e questo anche se è un Oggetto grafico (es. una ''Form'').
  
 
L'istruzione ''_new( )'' viene sempre eseguita, sia negli oggetti statici, che negli altri, solo che verrà eseguita esclusivamente alla prima chiamata di un qualsiasi loro metodo.
 
L'istruzione ''_new( )'' viene sempre eseguita, sia negli oggetti statici, che negli altri, solo che verrà eseguita esclusivamente alla prima chiamata di un qualsiasi loro metodo.

Versione delle 18:45, 4 nov 2021

Ogni oggetto ha alcuni metodi che possono essere utilizzati tranquillamente, e che corrispondono a precise fasi della vita dell'oggetto. [Nota 1] [Nota 2]

Quelli più importanti, sono:

Public Sub _New()

e

Public Sub _Free()

rispettivamente:

  • _New(): creazione dell'oggetto;
  • _Free(): distruzione dell'oggetto;
  • _New() può essere usato per passare dei parametri all'oggetto, proprio nella fase di creazione (non di apertura), e può essere utilizzato anche per creare oggetti all'interno di una Form.
  • _Free() viene chiamato giusto nella fase finale di eliminazione dell'oggetto dalla memoria. Può essere utilizzato, ad esempio, per terminare un timer (se si verifica un errore), oppure per chiudere un'attività, a prescindere dal resto.

Queste due funzioni, dunque, sono sempre e comunque chiamate (indipendentemete se dichiarate esplicitamente nel codice o meno) da Gambas, quando l'oggetto viene creato e distrutto, anche se non sono presenti nel codice dell'oggetto, perchè esistono comunque nella classe base di tutti gli oggetti creati in gambas (Object).

L'Oggetto deve essere esplicitamente creato, ovvero fornita sufficiente memoria per contenerlo, poi deve essere chiamato il suo costruttore. In Gambas questo procedimento è implicito con l'uso dell'istruzione NEW, che provoca prima la creazione in memoria dell'oggetto, poi esegue il suo costruttore, in tutti i casi il metodo _new().

Inoltre, ogni oggetto prevede anche un metodo distruttore, che in gambas viene assunto da un'altro metodo nascosto _free().
Gambas infine chiama automaticamente "_free()" e di "_delete()", quando l'Oggetto non viene più usato.

Il metodo _New()

Nel metodo _New() si possono definire e impostare i valori base e le proprietà dell'oggetto, e questo anche se è un Oggetto grafico (es. una Form).

L'istruzione _new( ) viene sempre eseguita, sia negli oggetti statici, che negli altri, solo che verrà eseguita esclusivamente alla prima chiamata di un qualsiasi loro metodo.

Il metodo _Free()

Il metodo _Free() è utilizzabile per pulire determinate situazioni (es. una connessione), che magari non sono state completate correttamente a causa di un'errore nella classe. Il metodo _Free() è in pratica il distruttore della classe, cioè viene chiamato un attimo prima che questa venga eliminata dalla memoria, ed è utile per pulire l'oggetto da riferimenti ad altre classi, o per chiudere eventuali aperture di stream.

All'interno di questo metodo, bisogna controllare (un IF di controllo può bastare sicuramente) se le variabili e le proprietà dello stesso siano ancora valide, ovvero non siano già state Nullate dalla procedura automatica di eliminazione dell'oggetto. Infatti potrebbe esserci una proprietà della classe che si sta cancellando, che punta ad un oggetto esterno che non è più valido. In questo caso, andando ad effettuare dei controlli su questa proprietà, in realtà si potrebbero trovare in due stadi:
1) la proprietà è ancora valida, ovvero il riferimento punta ad un oggetto ancora valido;

2) l'oggetto non esiste più, per cui il riferimento contiene un indirizzo non più valido, e quindi si potrebbe trovare Null oppure qualcosa di indefinito. In quest'ultimo caso è possibile usare i metodi di Object, per controllare in che stato l'oggetto sia.
Per riferimento si intende tutto quello che non è intrinseco alla classe stessa.
Se si ha una proprietà Button nella Form, che è stata inserita fissa tramite l'editor grafico di Gambas, questa viene eliminata automaticamente da Gambas.
Se si ha una variabile che contiene il riferimento ad un altro oggetto fuori della classe, Gambas non lo elimina, perchè potrebbe essere un oggetto valido, a prescindere dalla cancellazione di quella classe. In tal caso, se questo riferimento è da considerarsi non più utile, nel senso che il programmatore non lo intende valido, allora deve essere eliminato.
Se si ha una proprietà corrispondente ad un array di tipo String, questa viene pulita perchè contiene dati di livello base (String fa parte di questo gruppo, anche se è in realtà un oggetto).
Se si ha un array di tipo Integer, anche questa viene eliminata e pulita automaticamente.
Se però la proprietà contiene un oggetto che è utilizzato esclusivamente all'interno della classe, e non viene né instanziato, né utilizzato da codice esterno, allora anche questa proprietà viene pulita correttamente.


Facciamo un paio di esempi.

Come primo esempio poniamo il caso di avere due classi: Classe1 e Classe2.
Mettiamo che Classe2 abbia una proprietà di tipo Classe1, e che in qualche metodo gli venga assegnato un oggetto valido ovviamante dello stesso tipo. Quando si va ad eliminare Classe2, l'oggetto Classe1 è sempre vivo, perchè assegnato in maniera dinamica dall'esterno, quindi Gambas non può e non deve eliminarlo, in quanto è valido all'interno del progetto. In questo caso è necessario de-referenziare la proprietà della Classe2, mettendola a NULL, e quindi eliminando il puntamento.
Comunque, Classe1 continua sempre a vivere, e continuerà ad esserlo anche se viene posta a NULL la proprietà di Classe2, perchè non è essa quella che ha creato Classe1, ma ne teneva solo l'indirizzo in memoria.
L'eliminazione di Classe1 deve essere fatta solo da chi l'ha creata !

Nel secondo esempio, poniamo il caso di avere prima l'assegnazione del testo presente in una TextLabel1 alla proprietà .Text di un Button1, e successivamente la cancellazione di TextLabel1.Text.
In questo caso viene assegnato un valore stringa, che è un tipo di dato base, e che in Gambas viene passato come valore, quindi una copia conforme all'originale. Se si cancella TextLabel1.Text, il valore in Button1.Text viene mantenuto, perchè è un clone indipendente. Stessa cosa se si modifica l'uno rispetto all'altro, i due valori sono distinti, dalla copia in poi.
Se, mettiamo il caso che si intenda mantenere un riferimento all'oggetto TextLabel1, per generica utilità all'interno del progetto. Mettiamo quindi il caso sia stata creata una variabile $Txlb, a cui poi si assegni l'oggetto TextLabel1, questa variabile riceverà il puntatore a TextLabel1, ovvero l'indirizzo in memoria dell'oggetto TextLabel1 (non una copia), per cui qualsiasi operazione si fa attraverso $Txlb si rifletterà su TextLabel1. Se, mettiamo il caso, si decida di eliminare $Txlb, questo non eliminerà però l'oggetto originale, e quindi TextLabel1 continuerà ad esistere. Per tanto, se si intende eliminare TextLabel1, bisognerà per forza utilizzare la classe che lo contiene, di cui ha la paternità, e che avrà il compito di eliminare i suoi oggetti. Per lo stesso motivo, se elimina il padre, ad esempio una Form, questa eliminerà prima tutti i suoi children, e poi se stessa.
Ritornando alla variabile $Txlb, che mettiamo il caso sia di proprietà di una classe specifica. Se si va ad eliminare la detta classe specifica, bisognerà anche pulire tutti i riferimenti che ha, compresi quelli dei suoi figli. Quindi, essendo $Txlb un riferimento ad un oggetto esterno, bisognerà eliminare l'aggancio che $Txlb ha con questo oggetto, semplicemente mettendolo a Null (riferimento nullo, o void). Questa operazione è necessaria, in quanto Gambas non lo fa in questo caso, perchè non può sapere che uso si sta facendo della classe, ed è per questo motivo che ogni oggetto ha un metodo distruttore: appunto _Free().
In altri linguaggi il concetto è identico, anche se la sintassi è diversa. In C++ e Java, per esempio, la definizione del costruttore e del distruttore è obbligatoria, anche se non necessariamente codificata. Il costruttore è in pratica il punto d'ingresso della classe, e che si occupa dell'attivazione della stessa e dei suoi elementi. Il distruttore è quello che si occupa di eliminare tutte le tracce in memoria della classe, una volta che non serve più.

Come si è detto in precedenza, vanno fatti dei controlli, ma le operazioni vanno fatte solo se gli oggetti sono validi, e non se sono invalidi. Se v'è un oggetto valido, è possibile pulire la proprietà che lo contiene, relativa all'oggetto che contiene _free().
Riguardo al dopo non si deve fare nulla, e non si deve restituire nulla. Il metodo _free() non è reversibile, ma permette di fare gli ultimi ritocchi per pulire bene la memoria. A volte la pulizia automatica di Gambas non fa completamente il suo dovere, anche perché molte cose non può, e non deve, toccarle. A questo punto sta al programma controllare lo stato delle cose e agire di conseguenza. La mancata pulizia degli oggetti, fa sì che vengano emessi messaggi di warning alla chiusura dell'applicazione che, appunto, indicano che ci sono oggetti ancora attivi in memoria. La cosa, ad ogni modo, non è sia bloccante, è esclusivamente una questione di pulizia. Tutto quello che è stato utilizzato dal programma, viene ignorato dal sistema operativo, e reso mediamente disponibile.
Questo però non realmente valido, se vi sono dei processi in background, cui nessuno si occupa di eliminarli fisicamente dalla memoria. Di solito questi processi, se non vengono chiusi e puliti correttamente, restano come "zombie" nel sistema, e solo un "kill -9 " può eliminarli. ...ma per fortuna stiamo parlando di Linux, per cui processi impazziti non sono realmente un problema.


Passare dati ad un oggetto

Se si intende passare dati, è possibile scrivere la funzione in questo modo:

Public Sub _New(parm1 as String, parm2 AS String, ..., parm3 AS Integer)

End

all'interno possono essere assegnati i parametri ad altrettante proprietà dell'oggetto, o condizionarne il funzionamento (es. definire le dimensioni iniziali di una Form).



Note

[1] Riportiamo in questa pagina in modo più organico semplicemente diversi interventi e messaggi scritti su quest'argomento dall'utente md9327 del forum Gambas-it.org .

[2] Sull'argomento vedere anche e soprattutto la pagina, scritta sempre da md9327, della WIKI: Metodi nascosti.