Oppure

Loading

Tutti i tipi di variabile che possono essere creati si raggruppano sotto due grandi categorie: Reference e Value. I primi si comportano come oggetti, mentre i secondi rappresentano tipi scalari o numerici, ma vediamo di mettere un po' ordine in tutti questi concetti.
P.S.: per una migliore compresione di questo capitolo, consiglio solo a chi ha già esperienza nel campo della programmazione (in qualsiasi altro linguaggio) di leggere questo articolo sull'utilizzo della memoria da parte di un programma.


Differenza tra Classi e Oggetti

All'inizio della guida mi sono soffermato ad elogiare le classi e la loro enorme importanza nell'ambiente .NET. Successivamente ho fatto menzione al tipo System.Object e al fatto che ogni cosa sia un oggetto. La differenza tra oggetto e classe è di vitale importanza per capire come vanno le cose nell'ambito della programmazione OO. Una classe rappresenta l'astrazione di qualcosa di concreto; un oggetto, invece, è qualcosa di concreto e viene rappresentato da una classe. Per fare un esempio banale, sappiamo benissimo che esiste il concetto di "uomo", ma ogni individuo sul pianeta, pur mantenendo alcune caratteristiche simili e costanti, è differente rispetto agli altri. Facendo un parallelismo con la programmazione, quindi, il singolo individuo, ad esempio io stesso, è un oggetto, mentre il generale concetto di "uomo" che ognuno di noi conosce è la classe. Se qualcuno dei lettori ha studiato filosofia, riconoscerà in questa differenza la stessa che Platone identificava nella discrepanza tra mondo sensibile e Iperuranio. Avendo ben chiari questi concetti, si può ora introdurre un po' di gergo tecnico. Ogni oggetto è anche detto istanza della classe che lo rappresenta (voi siete istanze della classe Uomo XD) e istanziare un oggetto significa crearlo.

'New serve per creare fisicamente degli oggetti in memoria
Dim O1 As New Object
Dim O2 As New Object

O1 e O2 sono entrambe istanze della classe Object, ma sono diversi fra di loro: in comune hanno solo l'appartenenza allo stesso tipo.
N.B.: come si è notato, "tipo" e "classe" sono termini spesso equivalenti, ma non generalizzate questa associazione.


Tipi Reference

Ogni cosa nel Framework è un oggetto e la maggior parte di essi sono tipi reference. Si dicono tipi reference tutti quei tipi che derivano direttamente dalla classe System.Object (la "derivazione" appartiene a un concetto che spiegherò più avanti): questa classe è dichiarata all'interno di una libreria della Base Class Library, ossia l'archivio di classi del Framework. Nel capitolo precedente si è visto come sia possibile assegnare un valore ad una variabile utilizzando l'operatore uguale "=". Con questo meccanismo, un determinato valore viene depositato nella casella di memoria che la variabile occupa. Ebbene, facendo uso dei tipi reference, questo non avviene. Quando si utilizza l'uguale per assegnare un valore a tali variabili, quello che effettivamente viene riposto nella loro parte di memoria è un puntatore intero a 32bit (su sistemi operativi a 32bit). Per chi non lo sapesse, un puntatore è una speciale variabile che, invece di contenere un proprio valore, contiene l'indirizzo di un'area di memoria contenente altri dati. Il puntatore viene memorizzato come al solito sullo stack, mentre il vero oggetto viene creato e deposto in un'area di memoria differente, detta heap managed, dove esiste sotto la supervisione del CLR. Quando una variabile di questo tipo viene impostata a Nothing (una costante che vedremo tra poco), la parte dell'heap managed che l'oggetto occupa viene rilasciata durante il processo di garbage collection ("raccolta dei rifiuti"). Tuttavia, ciò non avviene subito, poichè il meccanismo del Framework fa in modo di avviare la garbage collection solo quando è necessario, quindi quando la memoria comincia a scarseggiare: supponendo che un programma abbia relativamente pochi oggetti, questi potrebbero "vivere" indisturbati fino alla fine del programma anche dopo essere stati logicamente distrutti, il che significa che è stato eliminato manualmente qualsiasi riferimento ad essi (vedi paragrafo successivo). Data l'impossibilità di determinare a priori quando un oggetto verrà distrutto, si ha un fenomeno che va sotto il nome di finalizzazione non deterministica (il termine "finalizzazione" non è casule: vedere il capitolo sui distruttori per maggiori informazioni).


Nothing

Nothing è una costante di tipo reference che rappresenta l'assenza di un oggetto piuttosto che un oggetto nullo. Infatti, porre una variabile oggetto uguale a Nothing equivale a distruggerla logicamente.

Dim O As New Object 'L'oggetto viene creato
O = Nothing 'L'oggetto viene logicamente distrutto

La distruzione logica non coincide con la distruzione fisica dell'oggetto (ossia la sua rimzione dalla memoria), poiché, come detto prima, il processo di liberazione della memoria viene avviato solo quando è necessario. Non è possibile assegnare Nothing a un tipo value, ma è possibile usare speciali tipi value che supportano tale valore: per ulteriori dettagli, vedere "Tipi Nullable".


Tipi Value

Ogni tipo value deriva dalla classe System.ValueType, che deriva a sua volta da System.Object, ma ne ridefinisce i metodi. Ogni variabile di questo tipo contiene effettivamente il proprio valore e non un puntatore ad esso. Inoltre, esse hanno dei vantaggi in termini di memoria e velocità: occupano in genere meno spazio; data la loro posizione sullo stack non vi è bisogno di referenziare un puntatore per ottenere o impostarne i valori (referenziare un puntatore significa recarsi all'indirizzo di memoria puntato e leggerne il contenuto); non c'è necessità di occupare spazio nello heap managed: se la variabile viene distrutta, cessa di esistere all'istante e non si deve attuare nessuna operazione di rilascio delle risorse. Notare che non è possibile distruggere logicamente una variabile value, fatta eccezione per certi tipi derivati.


Is e =

Nel lavorare con tipi reference e value bisogna prestare molta attenzione a quando si utilizzano gli operatori di assegnamento. Come già detto, i reference contengono un puntatore, perciò se si scrive questo codice:

Dim O1, O2 As Object
'...
O1 = O2

quello che O2 conterrà non sarà un valore identico a O1, ma un puntatore alla stessa area di memoria di O1. Questo provoca un fatto strano, poichè sia O1 che O2 puntano alla stessa area di memoria: quindi O1 e O2 sono lo stesso oggetto, soltanto riferito con nomi difersi. In casi simili, si può utilizzare l'operatore Is per verificare che due oggetti puntino allo stesso valore:

'Scrive a schermo se è vero oppure no che
'O1 e O2 sono lo stesso oggetto
Console.WriteLine(O1 Is O2)

La scritta che apparirà sullo schermo sarà "True", ossia "Vero". Utilizzare Is per comparare un oggetto a Nothing equivale a verificare che tale oggetto sia stato distrutto.
Questo NON avviene per i tipi value: quando ad un tipo value si assegna un altro valore con l'operatore =, si passa effettivamente una copia del valore. Non è possibile utilizzare Is con i tipi value poichè Is è definito solo per i reference.


Boxing e Unboxing

Consideriamo il seguente codice:

Dim I As Int32 = 50
Dim O As Object
O = I

I è un tipo value, mentre O è un tipo reference. Quello che succede dietro le quinte è semplice: il .NET crea un nuovo oggetto, perciò un tipo reference, con il rispettivo puntatore, e quindi gli assegna il valore di I: quando il processo è finito assegna il puntatore al nuovo oggetto a O. Questa conversione spreca tempo e spazio nello heap managed e viene definita come boxing. L'operazione inversa è l'unboxing e consiste nell'assegnare un tipo reference a un tipo value. Le operazioni che si svolgono sono le stesse, ma al contrario: entrambe sprecano tempo e cpu, quindi sono da evitare se non strettamente necessarie. Quando si può scegliere, quindi, sono meglio di tipi value.

A cura di: Il Totem