Beachten Sie, ob dies für Sie geeignet ist, aber in funktionalen Sprachen wie Standard ML ist standardmäßig alles unveränderlich. Die Mutation wird durch einen generischen ref
Erence-Typ unterstützt. Eine int
Variable ist also unveränderlich, und eine ref int
Variable ist ein veränderlicher Container für int
s. Grundsätzlich sind Variablen echte Variablen im mathematischen Sinne (ein unbekannter, aber fester Wert) und ref
s sind "Variablen" im imperativen Programmiersinn - eine Speicherzelle, in die geschrieben und aus der gelesen werden kann. (Ich nenne sie gerne zuweisbare Werte .)
Ich denke, das Problem const
ist zweifach. Erstens fehlt C ++ die Garbage Collection, die für nicht triviale persistente Datenstrukturen erforderlich ist . const
muss tief sein, um einen Sinn zu ergeben, aber es ist unpraktisch, vollständig unveränderliche Werte in C ++ zu haben.
Zweitens müssen Sie sich in C ++ anmelden const
anstatt sich dagegen zu entscheiden. Wenn Sie jedoch const
etwas vergessen und später korrigieren, werden Sie in die in der Antwort von @ RobY erwähnte "const poisoning" -Situation geraten, in der die const
Änderung im gesamten Code kaskadiert. Wenn dies const
der Standard wäre, würden Sie sich nicht const
rückwirkend bewerben . Außerdem führt das Hinzufügen von const
überall zu viel Rauschen im Code.
Ich vermute, dass die folgenden Mainstream-Sprachen (z. B. Java) stark vom Erfolg und der Denkweise von C und C ++ geprägt waren. Beispiel: Selbst bei der Garbage Collection gehen die meisten Collection-APIs von veränderlichen Datenstrukturen aus. Die Tatsache, dass alles veränderlich und unveränderlich ist, wird als Eckpfeiler angesehen und spricht Bände über die zwingende Denkweise hinter populären Sprachen.
EDIT : Nachdem ich über den Kommentar von greenoldman nachgedacht hatte, wurde mir klar, dass const
es nicht direkt um die Unveränderlichkeit von Daten geht. const
Codiert in den Typ der Methode, ob sie Nebenwirkungen auf die Instanz hat.
Mutationen können verwendet werden, um ein referenziell transparentes Verhalten zu erzielen . Angenommen, Sie haben eine Funktion, die beim sukzessiven Aufruf unterschiedliche Werte zurückgibt - zum Beispiel eine Funktion, aus der ein einzelnes Zeichen gelesen wird stdin
. Wir könnten die Ergebnisse dieser Funktion zwischenspeichern / auswendig lernen, um einen referenziell transparenten Strom von Werten zu erzeugen. Der Stream ist eine verknüpfte Liste, deren Knoten die Funktion aufrufen, wenn Sie zum ersten Mal versuchen, ihren Wert abzurufen, dann aber das Ergebnis zwischenspeichern. Also wennstdin
constains ist Hello, world!
, wird beim ersten Versuch, den Wert des ersten Knotens abzurufen, einer gelesen char
und zurückgegeben H
. Danach kehrt es H
ohne weitere Aufrufe weiter zum Lesen ein char
. Ebenso würde der zweite Knoten einen Fest char
ausstdin
Wenn Sie zum ersten Mal versuchen, seinen Wert abzurufen, wird dieses e
Ergebnis zurückgegeben und zwischengespeichert.
Das Interessante dabei ist, dass Sie einen Prozess, der von Natur aus zustandsbehaftet ist, in ein Objekt verwandelt haben, das scheinbar zustandslos ist. Es war jedoch notwendig, den internen Zustand des Objekts zu mutieren (indem die Ergebnisse zwischengespeichert wurden), um dies zu erreichen - die Mutation war ein harmloser Effekt . Es ist unmöglich, unseren zu CharStream
const
erzeugen, obwohl sich der Stream wie ein unveränderlicher Wert verhält . Stellen Sie sich vor, es gibt eine Stream
Schnittstelle mit const
Methoden und alle Funktionen, die Sie erwarten const Streams
. Sie CharStream
können die Schnittstelle nicht implementieren!
( EDIT 2: Anscheinend gibt es ein C ++ - Schlüsselwort mutable
, mit dem wir betrügen und machen könnenCharStream
const
. Jedoch zerstört diese Lücke die const
Garantien - jetzt können Sie wirklich nicht sicher sein, dass etwas durch seine const
Methoden nicht mutiert . Ich nehme an, dass es nicht so ist schlecht, da Sie die Lücke explizit beantragen müssen, aber immer noch voll und ganz auf das Ehrensystem angewiesen sind.)
Angenommen, Sie haben Funktionen höherer Ordnung, dh Sie können Funktionen als Argumente an andere Funktionen übergeben. const
ness ist Teil der Signatur einer Funktion, sodass Sie keineconst
als Argumente an Funktionen übergeben, die const
Funktionen erwarten . Eine blinde Durchsetzung const
würde zu einem Verlust der Allgemeinheit führen.
Schließlich manipulieren a const
garantiert das Objekts nicht, dass es keinen externen (statischen oder globalen) Zustand hinter Ihrem Rücken mutiert, sodass const
die Garantien nicht so stark sind, wie sie anfänglich angezeigt werden.
Mir ist nicht klar, dass es allgemein gut ist, das Vorhandensein oder Nichtvorhandensein von Nebenwirkungen in das Typsystem zu kodieren.