2009-06-22 17 views
8

Mi piace il concetto di immutabilità, ma a volte mi chiedo, quando un'applicazione non intende essere parallela, si dovrebbe evitare di rendere le cose immutabili?L'immutabilità è utile su applicazioni non parallele?

Quando un'applicazione non è multi-thread, non si è afflitti da problemi di stato condivisi, giusto?

O è immutabilità un concetto come OOP che usi o no? Escludere i casi in cui qualcosa non dovrebbe essere immutabile in base all'utilizzo/alle prestazioni, ecc.

Sono di fronte a questa domanda quando scrivo un'applicazione per me, che è moderatamente grande (forse come le linee 1-2k).

+8

Lo stato immutabile è utile per le applicazioni con multithreading perché è più facile ragionare sulla correttezza dello stato immutabile in scenari multithread. Ma è anche più facile ragionare sulla correttezza dello stato immutabile in scenari a thread singolo! È semplicemente più facile ragionare su cose che non cambiano di quanto non sia per ragionare su cose che cambiano. –

+0

@Eric: lol. . –

risposta

8

Amo l'immutabilità perché significa che non devo fidarmi del codice di altri popoli per non scherzare con oggetti che mi aspetto di rimanere lo stesso.

Quando si passa un oggetto a un altro componente come ad esempio List<T>, si è in balia di ciò che fa quel componente. Questo è particolarmente importante quando si restituiscono le raccolte come proprietà.

public class Foo { 
    private List<Bar> _barList; 
    public ICollection<Bar> BarList { get return _barList; } 
} 

Non c'è niente di fermare un consumatore di questa classe dalla compensazione della collezione da sotto di me. Anche la commutazione del tipo di ritorno su IEnumerable<Bar> non è completamente sicura. Non c'è niente che ferma un pezzo di codice scritto male da restituire a List<T> e chiamando .Clear().

Tuttavia, se voglio davvero la collezione di rimanere coerente potrei riscriverlo come followis

public class Foo { 
    private ImmutableCollection<Bar> _barList; 
    public ImmutableCollection<Bar> BarList { get { return _barList; } } 
} 

Ora sono al sicuro da dover fidarsi altro codice di usare la mia classe in modo non corretto. Non possono rovinarlo.

+0

ImmutableCollection in BCL? O solo un esempio? –

+1

@ Joan, proviene da una biblioteca che possiedo. È disponibile all'indirizzo http://code.msdn.microsoft.com/BclExtras – JaredPar

+0

Grazie a Jared, lo scaricherà. –

9

Mi piace il vantaggio dell'immutabilità che è necessario convalidarlo solo una volta - alla creazione dell'oggetto. Questo è davvero un enorme bonus.

+6

Buon punto. Questa idea ha anche implicazioni sulla sicurezza. Supponiamo di passare un oggetto mutabile X al metodo Foo. Foo controlla X per assicurarsi che X sia un argomento valido per Foo, gira se non lo è, e quindi esegue alcune operazioni sensibili alla sicurezza basate su X. Se un chiamante ostile può mutare X su un altro thread dopo il controllo degli argomenti, il controllo degli argomenti può essere aggirato efficacemente! Questo è uno dei motivi per cui le stringhe sono immutabili in .NET - vuoi essere in grado di dire "apri questo file", fare un controllo di sicurezza su quel percorso e sapere che la stringa del percorso non cambierà tra il controllo e il file aperto . –

+0

Per fare ciò, si usa il modello di fabbrica statico ... sincronizzato. –

2

Un importante vantaggio dell'immutabilità è che non è necessario tenere traccia della proprietà di oggetti immutabili. Esiste solo finchè qualcuno ha bisogno di loro, e poi svanisce nel nulla quando non sono più necessari. In molti casi l'uso di un garbage collector significa che non è necessario scrivere alcun codice esplicito relativo alla proprietà di oggetti mutabili (la più grande eccezione è quella che implementa IDisposable), in molti casi è molto difficile scrivere codice corretto in cui gli oggetti che hanno lo stato mutabile non ha un "proprietario" chiaramente definito. La confusione su chi possiede lo stato degli oggetti mutabili può essere una fonte molto frequente di bug; quando si usano oggetti immutabili (a parte alcuni che implementano IDisposable) si può generalmente ignorare i problemi di proprietà.

altro punto da considerare è che è molto più facile ragionare su un riferimento mutevole a un oggetto semanticamente immutabile, o un riferimento immutabile di un oggetto mutabile, che è di ragionare su un riferimento mutevole ad un oggetto mutabile. Se si ha un riferimento mutabile a un oggetto mutabile, spesso non è chiaro se l'approccio corretto all'aggiornamento dello stato consiste semplicemente nel mutare l'oggetto direttamente, oppure copiare il suo stato in un nuovo oggetto, mutarlo e aggiornare il riferimento. In alcuni casi, ci saranno circostanze che richiedono ogni tipo di operazione (come con List<T>, che a volte sostituisce una matrice con una più grande, ma di solito aggiorna sul posto), ma tale approccio funziona solo se il tipo mantiene il controllo esclusivo su gli oggetti mutabili in questione.Spesso è più utile avere un riferimento immutabile a un tipo mutabile (nel qual caso il codice può esporre il riferimento, possibilmente attraverso un wrapper di sola lettura, ad altri oggetti che vogliono una "vista live" del suo stato) oppure avere un riferimento mutabile a un oggetto che è immutabile o che, almeno, non sarà mai mutato durante la vita del riferimento.