Un punto importante non ancora menzionato è che avere lo stato di un oggetto essere mutabile rende possibile che l' identità dell'oggetto che incapsula quello stato sia immutabile.
Molti programmi sono progettati per modellare cose del mondo reale che sono intrinsecamente mutabili. Supponiamo che alle 12:51, alcune variabili AllTrucks
contengano un riferimento all'oggetto # 451, che è la radice di una struttura di dati che indica quale carico è contenuto in tutti i camion di una flotta in quel momento (12:51) e alcune variabili BobsTruck
può essere usato per ottenere un riferimento all'oggetto # 24601 punti a un oggetto che indica quale carico è contenuto nel camion di Bob in quel momento (00:51). Alle 12:52, alcuni camion (incluso quello di Bob) vengono caricati e scaricati e le strutture dei dati vengono aggiornate in modo tale da AllTrucks
contenere un riferimento a una struttura di dati che indica che il carico è in tutti i camion a partire dalle 12:52.
Cosa dovrebbe succedere BobsTruck
?
Se la proprietà 'cargo' di ogni oggetto camion è immutabile, l'oggetto # 24601 rappresenterà per sempre lo stato che il camion di Bob aveva alle 12:51. Se BobsTruck
contiene un riferimento diretto all'oggetto # 24601, a meno che AllTrucks
anche il codice che aggiorna non venga aggiornato BobsTruck
, cesserà di rappresentare lo stato corrente del camion di Bob. Si noti inoltre che, a meno che non BobsTruck
sia memorizzato in una qualche forma di oggetto mutabile, l'unico modo in cui il codice che AllTrucks
potrebbe essere aggiornato potrebbe essere se il codice fosse esplicitamente programmato per farlo.
Se si vuole essere in grado di BobsTruck
osservare lo stato del camion di Bob mantenendo immutabili tutti gli oggetti, si potrebbe avere BobsTruck
una funzione immutabile che, dato il valore che AllTrucks
ha o ha avuto in un determinato momento, produrrà lo stato del camion di Bob a quella volta. Uno potrebbe anche avere un paio di funzioni immutabili - una delle quali sarebbe come sopra, e l'altra accetterebbe un riferimento a uno stato di flotta e un nuovo stato di camion e restituire un riferimento a un nuovo stato di flotta che abbinato al vecchio, tranne per il fatto che il camion di Bob avrebbe il nuovo stato.
Sfortunatamente, dover usare una tale funzione ogni volta che si vuole accedere allo stato del camion di Bob potrebbe diventare piuttosto fastidioso e ingombrante. Un approccio alternativo sarebbe quello di dire che l'oggetto # 24601 rappresenterà sempre e per sempre (purché qualcuno ne abbia un riferimento) rappresenterà lo stato attuale del camion di Bob. Il codice che vorrà accedere ripetutamente allo stato attuale del camion di Bob non dovrebbe eseguire ogni volta una funzione che richiede molto tempo: potrebbe semplicemente fare una funzione di ricerca una volta per scoprire che l'oggetto # 24601 è il camion di Bob, e quindi semplicemente accedi a quell'oggetto ogni volta che vuole vedere lo stato attuale del camion di Bob.
Si noti che l'approccio funzionale non è privo di vantaggi in un ambiente a thread singolo o in un ambiente a thread multipli in cui i thread osserveranno principalmente i dati anziché modificarli. Qualsiasi thread osservatore che copia il riferimento all'oggetto contenuto inAllTrucks
e quindi esamina gli stati dei camion rappresentati, quindi vedrà lo stato di tutti i camion dal momento in cui ha afferrato il riferimento. Ogni volta che un thread di osservatori desidera visualizzare dati più recenti, può semplicemente riottenere il riferimento. D'altro canto, avere l'intero stato della flotta rappresentato da un singolo oggetto immutabile impedirebbe la possibilità che due thread aggiornino contemporaneamente diversi camion, poiché ogni thread se lasciato ai propri dispositivi produrrebbe un nuovo oggetto "stato flotta" che includeva il nuovo stato del suo camion e i vecchi stati di ogni altro. La correttezza può essere garantita se ogni thread utilizza CompareExchange
per aggiornare AllTrucks
solo se non è cambiato e risponde a un erroreCompareExchange
rigenerando il suo oggetto stato e ritentando l'operazione, ma se più di un thread tenta un'operazione di scrittura simultanea, le prestazioni saranno generalmente peggiori rispetto a se tutte le scritture fossero eseguite su un singolo thread; più thread tentano tali operazioni simultanee, peggiore sarà la prestazione.
Se i singoli oggetti del camion sono mutabili ma hanno identità immutabili , lo scenario multi-thread diventa più pulito. È possibile consentire a un solo thread di funzionare alla volta su un determinato camion, ma i thread che operano su camion diversi potrebbero farlo senza interferenze. Mentre ci sono modi in cui si potrebbe emulare tale comportamento anche quando si utilizzano oggetti immutabili (ad esempio si potrebbero definire gli oggetti "AllTrucks" in modo che l'impostazione dello stato del camion appartenente a XXX su SSS richiederebbe semplicemente la generazione di un oggetto che dicesse "A partire da [Time], lo stato del camion appartenente a [XXX] è ora [SSS]; lo stato di tutto il resto è [Vecchio valore di AllTrucks] ". La generazione di un tale oggetto sarebbe abbastanza veloce che anche in presenza di contesa, unCompareExchange
il ciclo non richiederebbe molto tempo. D'altra parte, l'utilizzo di una tale struttura di dati aumenterebbe sostanzialmente il tempo necessario per trovare il camion di una persona in particolare. L'uso di oggetti mutabili con identità immutabili evita questo problema.