Hai uno stato quando associ valori (numeri, stringhe, strutture dati complesse) a un'identità e un punto nel tempo.
Ad esempio, il numero 10 da solo non rappresenta alcuno stato: è solo un numero ben definito e sarà sempre se stesso: il numero naturale 10. Come altro esempio, la stringa "CIAO" è una sequenza di cinque caratteri, e è completamente descritto dai caratteri che contiene e dalla sequenza in cui appaiono. Tra cinque milioni di anni, la stringa "CIAO" sarà ancora la stringa "CIAO": un valore puro.
Per avere uno stato devi considerare un mondo in cui questi valori puri sono associati a un qualche tipo di entità che possiede un'identità . L'identità è un'idea primitiva: significa che puoi distinguere due cose indipendentemente dalle altre proprietà che possono avere. Ad esempio, due auto dello stesso modello, stesso colore, ... sono due auto diverse.
Date queste cose con identità, è possibile associare proprietà ad esse, descritte da valori puri. Ad esempio, la mia macchina ha la proprietà di essere blu. Puoi descrivere questo fatto associando la coppia
("colour", "blue")
alla mia macchina. La coppia ("colore", "blu") è un valore puro che descrive lo stato di quella particolare auto.
Lo stato non è associato solo a una particolare entità, ma anche a un determinato momento. Quindi, puoi dire che oggi la mia macchina ha stato
("colour", "blue")
Domani lo farò ridipingere in nero e lo sarà il nuovo stato
("colour", "black")
Si noti che lo stato di un'entità può cambiare, ma la sua identità non cambia per definizione. Bene, finché esiste l'entità, ovviamente: un'auto può essere creata e distrutta, ma manterrà la sua identità per tutta la sua vita. Non ha senso parlare dell'identità di qualcosa che non esiste ancora / non più.
Se i valori delle proprietà associate a una determinata entità cambiano nel tempo, si dice che lo stato di tale entità è mutabile . Altrimenti, dici che lo stato è immutabile .
L'implementazione più comune è quella di memorizzare lo stato di un'entità in un qualche tipo di variabili (variabili globali, variabili dei membri dell'oggetto), ovvero memorizzare l' istantanea corrente di uno stato. Lo stato mutabile viene quindi implementato usando l'assegnazione: ogni operazione di assegnazione sostituisce la precedente istantanea con una nuova. Questa soluzione utilizza normalmente posizioni di memoria per memorizzare l'istantanea corrente. La sovrascrittura di una posizione di memoria è un'operazione distruttiva che sostituisce un'istantanea con una nuova. ( Qui puoi trovare un discorso interessante su questo approccio di programmazione orientato al luogo.)
Un'alternativa è quella di visualizzare gli stati successivi (storia) di un'entità come un flusso (possibilmente sequenza infinita) di valori, vedere ad esempio il capitolo 3 del SICP . In questo caso, ogni istantanea viene memorizzata in una diversa posizione di memoria e il programma può esaminare contemporaneamente diverse istantanee. Le istantanee non utilizzate possono essere raccolte in modo inutile quando non sono più necessarie.
Vantaggi / svantaggi dei due approcci
- L'approccio 1 consuma meno memoria e consente di costruire una nuova istantanea in modo più efficiente poiché non richiede alcuna copia.
- L'approccio 1 spinge implicitamente il nuovo stato a tutte le parti di un programma che ne contenga un riferimento, l'approccio 2 avrebbe bisogno di un meccanismo per inviare un'istantanea ai suoi osservatori, ad esempio sotto forma di un evento.
- L'approccio 2 può aiutare a prevenire errori di stato incoerenti (ad es. Aggiornamenti di stato parziali): definendo una funzione esplicita che produce un nuovo stato da uno vecchio è più facile distinguere tra istantanee prodotte in diversi punti nel tempo.
- L'approccio 2 è più modulare in quanto consente di produrre facilmente viste sullo stato che sono indipendenti dallo stato stesso, ad esempio utilizzando funzioni di ordine superiore come
map
e filter
.