Immutability (Unveränderlichkeit) bedeutet: Ein Datenwert wird nach seiner Erzeugung niemals verändert. Jede Operation, die einen Wert „ändern“ möchte, erzeugt stattdessen einen neuen Wert — der ursprüngliche bleibt unangetastet. Das ist ein Kernprinzip der funktionalen Programmierung.
Warum unveränderlich?
- Thread-Sicherheit ohne Sperren: Unveränderliche Werte können von mehreren Threads gleichzeitig gelesen werden, ohne dass Nebenläufigkeit zu Race Conditions führt. Sie sind von Natur aus thread-sicher.
- Einfacheres Nachvollziehen: Wer einen Wert übergibt, kann sicher sein, dass er sich nicht heimlich ändert — keine versteckten Seiteneffekte, leichter zu testen und zu debuggen.
- Zeitreisen beim Debugging: Frühere Zustände bleiben erhalten und lassen sich jederzeit reproduzieren.
Persistente Datenstrukturen
Damit Unveränderlichkeit nicht teuer wird, nutzen funktionale Sprachen persistente Datenstrukturen mit structural sharing: Neue Versionen teilen sich unveränderte Teile der alten Struktur, statt sie komplett zu kopieren. Ein bekanntes Beispiel ist der HAMT (Hash Array Mapped Trie) für Maps — verwendet in Clojure, Erlang und Elixir. So kostet ein „Update“ nur einen kleinen Teil der Struktur statt einer vollen Kopie.
Immutability im Alltag
Auch außerhalb funktionaler Sprachen begegnet man dem Prinzip: Java-Strings sind unveränderlich, const und Object.freeze() in JavaScript schränken Veränderung ein, React-State wird als unveränderlich behandelt, und Git verwaltet unveränderliche Commits.
Abgrenzung
Immutability ist nicht „keine Veränderung“ im Sinne von Stillstand: Programme sollen natürlich Zustand entwickeln. Gemeint ist, dass Veränderung explizit und lokal geschieht — neue Werte entstehen, alte bleiben. Zusammen mit Currying und Higher-Order-Funktionen bildet das die Grundlage eines deklarativen, komponierbaren Programmierstils.