Hai uno stato quando si associano valori (numeri, stringhe, strutture dati complesse) a un'identità ea un punto nel tempo.
Ad esempio, il numero 10 di per sé non rappresenta nessuno 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, ed è completamente descritto dai personaggi 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 qualche tipo di entità che possiedono un'identità .
L'identità è un'idea primitiva: significa che puoi distinguere due cose indipendentemente da altre proprietà che possono avere. Ad esempio, due auto dello stesso modello, dello stesso colore, ... sono due auto diverse.
Considerate queste cose con identità, è possibile associarvi delle proprietà, 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 ("color", "blue") è un valore puro che descrive lo stato di quella particolare macchina.
Lo stato non è solo associato a una particolare entità, ma anche a un particolare punto temporale. Quindi, oggi puoi dire che la mia macchina ha lo stato
("colour", "blue")
Domani lo rivernerò in nero e il nuovo stato sarà
("colour", "black")
Tieni presente che lo stato di un'entità può cambiare, ma la sua identità non cambia per definizione. Bene, finché esiste l'entità, naturalmente: un'auto può essere creata e distrutta, ma manterrà la sua identità per tutta la sua durata. Non ha senso parlare dell'identità di qualcosa che ancora non esiste più.
Se i valori delle proprietà associate a una data entità cambiano nel tempo, tu dici che lo stato di tale entità è mutabile . Altrimenti, dici che lo stato è immutable .
L'implementazione più comune è quella di memorizzare lo stato di un'entità in una sorta di variabili (variabili globali, variabili membro dell'oggetto), ad esempio per memorizzare lo snapshot corrente di uno stato. Lo stato mutabile viene quindi implementato utilizzando l'assegnazione: ogni operazione di assegnazione sostituisce l'istantanea precedente 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 interessante discorso su questo approccio programmazione orientata al luogo .)
Un'alternativa è vedere gli stati successivi (storia) di un'entità come uno stream (possibilmente una sequenza infinita) di valori, vedi per es. Capitolo 3 di SICP .
In questo caso, ciascuna istantanea viene archiviata in una diversa posizione di memoria e il programma può esaminare diverse istantanee contemporaneamente. Le istantanee non utilizzate possono essere raccolte automaticamente 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 comporta alcuna copia.
- L'approccio 1 spinge implicitamente il nuovo stato in tutte le parti di un programma che contiene un riferimento ad esso, l'approccio 2 avrebbe bisogno di un meccanismo per spingere un'istantanea ai suoi osservatori, ad es. sotto forma di un evento.
- L'approccio 2 può aiutare a prevenire errori di stato inconsistenti (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 momenti diversi.
- L'approccio 2 è più modulare in quanto consente di produrre facilmente viste sullo stato che sono indipendenti dallo stato stesso, ad es. utilizzando funzioni di ordine superiore come
map
e filter
.