Unveränderliche Objekte vs. unveränderliche Sammlungen
Einer der Feinheiten in der Debatte über veränderbare und unveränderliche Objekte ist die Möglichkeit, das Konzept der Unveränderlichkeit auf Sammlungen auszudehnen. Ein unveränderliches Objekt ist ein Objekt, das häufig eine einzelne logische Datenstruktur darstellt (z. B. eine unveränderliche Zeichenfolge). Wenn Sie einen Verweis auf ein unveränderliches Objekt haben, ändert sich der Inhalt des Objekts nicht.
Eine unveränderliche Sammlung ist eine Sammlung, die sich nie ändert.
Wenn ich eine Operation für eine veränderbare Sammlung ausführe, ändere ich die Sammlung an Ort und Stelle, und alle Entitäten, die Verweise auf die Sammlung haben, sehen die Änderung.
Wenn ich eine Operation für eine unveränderliche Sammlung ausführe, wird eine Referenz auf eine neue Sammlung zurückgegeben, die die Änderung widerspiegelt. Alle Entitäten, die Verweise auf frühere Versionen der Sammlung haben, sehen die Änderung nicht.
Clevere Implementierungen müssen nicht unbedingt die gesamte Sammlung kopieren (klonen), um diese Unveränderlichkeit zu gewährleisten. Das einfachste Beispiel ist der als einfach verknüpfte Liste implementierte Stapel und die Push / Pop-Operationen. Sie können alle Knoten aus der vorherigen Sammlung in der neuen Sammlung wiederverwenden, indem Sie nur einen einzigen Knoten für den Push hinzufügen und keine Knoten für den Pop klonen. Die push_tail-Operation für eine einfach verknüpfte Liste ist dagegen nicht so einfach oder effizient.
Unveränderliche vs. veränderbare Variablen / Referenzen
Einige funktionale Sprachen verwenden das Konzept der Unveränderlichkeit für Objektreferenzen selbst und erlauben nur eine einzige Referenzzuweisung.
- In Erlang gilt dies für alle "Variablen". Ich kann einer Referenz nur einmal Objekte zuweisen. Wenn ich eine Sammlung bearbeiten würde, könnte ich die neue Sammlung nicht der alten Referenz (Variablenname) zuweisen.
- Scala baut dies auch in die Sprache ein, wobei alle Referenzen mit var oder val deklariert werden , wobei vals nur eine einzelne Zuweisung sind und einen funktionalen Stil fördern, vars jedoch eine C-ähnliche oder Java-ähnliche Programmstruktur ermöglichen.
- Die var / val-Deklaration ist erforderlich, während viele traditionelle Sprachen optionale Modifikatoren wie final in Java und const in C verwenden.
Einfache Entwicklung vs. Leistung
Fast immer besteht der Grund für die Verwendung eines unveränderlichen Objekts darin, die nebenwirkungsfreie Programmierung und das einfache Denken über den Code zu fördern (insbesondere in einer Umgebung mit hoher Parallelität / Parallelität). Sie müssen sich keine Sorgen machen, dass die zugrunde liegenden Daten von einer anderen Entität geändert werden, wenn das Objekt unveränderlich ist.
Der Hauptnachteil ist die Leistung. Hier ist eine Zusammenfassung eines einfachen Tests, den ich in Java durchgeführt habe , um einige unveränderliche mit veränderlichen Objekten in einem Spielzeugproblem zu vergleichen.
Die Leistungsprobleme sind in vielen Anwendungen umstritten, aber nicht in allen, weshalb viele große numerische Pakete, wie die Numpy Array-Klasse in Python, direkte Aktualisierungen großer Arrays ermöglichen. Dies wäre wichtig für Anwendungsbereiche, die große Matrix- und Vektoroperationen verwenden. Diese großen datenparallelen und rechenintensiven Probleme erreichen eine große Beschleunigung, wenn sie an Ort und Stelle arbeiten.
string
ist unveränderlich, zumindest in .NET, und ich denke auch in vielen anderen modernen Sprachen.