Per definire correttamente le classi mutevoli e immutabili, è necessario prima definire cosa significa per un oggetto istanza essere mutabile. Un'istanza dell'oggetto è mutabile se esiste un qualsiasi possibile mezzo (*) tramite il quale lo stato incapsulato potrebbe essere modificato. Un'istanza dell'oggetto è immutabile se il suo stato non può essere modificato. Una classe è immutabile se tutte le istanze di quella classe sono garantite come immutabili, indipendentemente da chi potrebbe contenere riferimenti a esse.
(*) Esistono alcuni approcci come Reflection in cui il codice dannoso potrebbe modificare qualsiasi cosa; la maggior parte delle discussioni sull'immutabilità si concentrano su cose che il codice può "legittimamente" fare e considerano illegittimi tali trucchi di riflessione. Al di fuori delle applicazioni di sicurezza, l'obiettivo normale è far funzionare correttamente gli oggetti per i client ben educati; se una classe si comporta in modo strano quando i client fanno cose illegittime, questo è il problema dei clienti.
Molte discussioni sull'immutabilità ignorano il fatto che mentre tutte le istanze di una classe immutabile sono immutabili, le istanze di una classe mutabile possono anche essere immutabili. Alcune discussioni sulla mutabilità suggeriscono che per una classe "davvero" immutabile, tutti i suoi campi devono essere anche tipi immutabili. Non solo non è vero, ma in molti casi rappresenterebbe un obiettivo quasi impossibile data l'assenza di tipi di array immutabili. Ciò che è necessario è che un oggetto immutabile deve sempre essere certo che nessun riferimento a nessun oggetto mutabile in cui è stato mantenuto lo stato sarà mai esposto a un codice che potrebbe mutarlo. Tutto ciò che il codice esterno potrebbe legittimamente voler fare con l'oggetto incapsulato deve essere fatto attraverso metodi implementati da o per conto dell'oggetto contenente immutabile.
Sarebbe utile se .NET o Java avessero mezzi dichiarativi per specificare che certi oggetti, nonostante siano di tipo mutabile, non dovrebbero mai essere modificati. Sfortunatamente, nessuna di queste funzionalità esiste. Nonostante ciò, una chiave importante per scrivere codice corretto ed efficiente è sapere quali riferimenti identificano cose che sono note come di classi immutabili, quali identificano (quali devono essere) istanze immutabili di classi possibilmente mutevoli, che identificano istanze mutabili non condivise di classi mutevoli e quali non si adattano a nessuno di questi modelli (generalmente perché identificano le "entità"). Molti tipi di bug, alcuni dei quali possono essere molto oscuri, possono derivare dall'uso di uno dei tipi di riferimento sopra indicati come se fosse un altro.
PS - Un framework può raggiungere l'efficienza e la robustezza della convalida const senza i problemi di C ++ - stile "const correctness" se
-
Esistono tipi di archiviazione distinti per "riferimenti all'entità", "riferimento illimitato a valore potenzialmente mutabile", "riferimento di sola lettura a valore potenzialmente mutevole" e "riferimento a valore immutabile"
-
I valori sono clonabili [la clonazione potrebbe essere ampiamente automatizzata se i tipi di riferimenti contenuti sono distinti]
-
I membri possono essere contrassegnati in base al fatto che dovrebbero essere richiamabili su riferimenti di sola lettura o immutabili
-
Ogni istanza di un oggetto include un flag che dice se esistono riferimenti non limitati ad esso
-
Qualsiasi riferimento può essere convertito implicitamente in un riferimento di sola lettura; un riferimento senza restrizioni può anche essere implicitamente convertito in un riferimento immutabile creando un nuovo clone immutabile. Un riferimento di sola lettura può essere convertito implicitamente in immutabile, creando un nuovo clone immutabile, se necessario. Un nuovo oggetto mutevole può essere clonato da qualsiasi riferimento.
Un aspetto essenziale della distinzione "entità" rispetto a "valore" sarebbe che un oggetto è un "valore" solo se (1) è immutabile, o (2) ha un proprietario singolo, e nessun riferimento di alcun tipo esiste all'oggetto che non è sotto il controllo di quel proprietario. Cercare di riguadagnare il controllo su tutti i riferimenti che potrebbero esistere a un oggetto che è stato esposto liberamente al codice esterno sarebbe impossibile, e un meccanismo strettamente applicato al compilatore sarebbe probabilmente troppo restrittivo per essere utile, ma anche se le cose funzionassero come C ++ "cost-correttezza" in cui il codice potrebbe promettersi di comportarsi con una semantica corretta anche quando sembrava "sospetto", ma qualsiasi problema che ne deriverebbe sarebbe colpa del fatto che il programmatore infrangesse la sua promessa, sarebbe un vantaggio significativo rispetto allo status quo. / p>