Die Unveränderlichkeit ist seit einiger Zeit bekannt. Python, Java und C ++ haben unterschiedliche Speichermodelle, die direkte Vergleiche erschweren. Der Autor des Artikels, den Sie ursprünglich zitiert haben , scheint C ++ nicht zu kennen.
Wie in Python, Java und den meisten Sprachen mit mehreren Paradigmen ermöglichen C und C ++ standardmäßig die Veränderbarkeit. Dies ist, was Programmierer normalerweise wollen: Wenn ich eine String x
Variable habe, möchte ich in der Lage sein, einen neuen Wert zuzuweisen x = "foo"
.
Das const-System in C und C ++ ermöglicht eine Menge nuancierter Unveränderlichkeit, die in Python, Java und sogar Scala fehlt. Wenn eine C ++ - Funktion a const std::string&
oder a benötigt const char*
, verspricht sie (und der Compiler stellt bis zu einem gewissen Grad sicher), dass diese Funktion den Inhalt dieser Zeichenfolge nicht ändert (kann!). Bei einem gegebenen const-Objekt können wir nur Methoden dieses Objekts aufrufen, die auch als const markiert sind. Wenn eine C ++ - Klasse nur öffentliche Mitglieder hat const
, ist das Objekt effektiv unveränderlich.
Dies ist jedoch manchmal verwirrend, da in C und C ++ Objekte Speicherorte sind und Variablen Namen für Speicherorte sind. Im Gegensatz dazu sind Variablen in Python und Java Namen für Zeiger auf Objekte. In einer Sprache mit Referenzsemantik x = y
bedeutet dies, dass x auf dasselbe Objekt wie y zeigt. Da wir nur Zeiger kopieren, ist dies mit unveränderlichen Objekten möglich. In einer Sprache mit Wertesemantik wie C ++ bedeutet dies "Aktualisieren des Inhalts von x
mit dem Inhalt von y
". Wenn daher eine Neuzuweisung einer Variablen in C oder C ++ gewünscht wird, hat die Variable möglicherweise keinen const-Typ. Um dies mit unveränderlichen Objekten zu tun, müssten wir explizit einen Zeiger verwenden.
Dass Java und Python unveränderliche Zeichenfolgenobjekte verwenden, ist eine grundlegende Entwurfsentscheidung, hängt jedoch nicht direkt mit den Vorteilen der Unveränderlichkeit in einer Multithreading-Umgebung zusammen. Ein Grund dafür ist, dass Zeichenfolgenliterale im Quellcode zusammengefasst werden können, wodurch die Anzahl der Objekte verringert wird. Dies ist auch in C / C ++ möglich. In C ++ hat das Literal "foo"
den Typ const char[4]
(das 4. Zeichen ist das Beenden '\0'
). Ein weiterer Grund ist, dass Einträge in Sets und Schlüssel in Diktaten / Karten nicht geändert werden dürfen. Da Zeichenfolgen häufig als Diktatschlüssel verwendet werden (die meisten Python-Objekte sind Diktatschlüssel), wird durch die Unveränderlichkeit eine häufige Fehlerquelle beseitigt. In Java ist das Java-Sicherheitsmodell ein weiterer Grund für unveränderliche Zeichenfolgen. All diese Gründe haben nichts mit Multithreading zu tun.
Wenn Java mit Blick auf Unveränderlichkeit erstellt worden wäre, hätte die Sprache ganz anders ausgesehen. Obwohl es stark von C ++ inspiriert ist, haben die Designer versucht, eine viel einfachere Sprache zu erstellen. Die Beseitigung von const ist ein solcher Schritt. Das Java-Äquivalent zu einer C ++ - Konstantenreferenz ist ein Adapter oder Dekorator, der alle Mutationsmethoden als implementiert throws new NotImplementedException()
und nicht mutierende Methodenaufrufe an die eigentliche Sammlung weiterleitet. Die Tatsache, dass die java.util-Auflistung alle Schnittstellen impliziert, ist ein klares Zeichen dafür, dass sie nicht nach einer unveränderlichen Sprache strebten.
Die Lösung, die Java zur Lösung von Parallelitätsproblemen vorschlug, war nicht Unveränderlichkeit, sondern allgegenwärtiges Sperren. Jedes einzelne Objekt enthält einen Mutex, der für synchronized
Blöcke oder ganze Methoden verwendet werden kann. Wie sich herausstellt, ist das nicht gut für die Leistung, skaliert nicht sehr gut und ist ziemlich fehleranfällig - Sie müssen sich immer noch mit veränderlichen globalen Zuständen auseinandersetzen.