Ich interessiere mich für die Idee von C ++ - wie const
nicht diese bestimmte Ausführung (wie das Wegwerfen const
).
Nehmen Sie zum Beispiel C # - es fehlt C ++ - wie const, und der Grund dafür ist das übliche - Menschen und Zeit. Hier scheint es, dass das C # -Team sich die C ++ - Ausführung von const
Marketing-CLR angeschaut hat und an diesem Punkt genug hatte (siehe, warum es keine const-Member-Methode in c # und const -Parametern gibt ; danke, Svick). Seien Sie, wenn wir uns weiter bewegen, ist etwas anderes?
Gibt es etwas tieferes? Nehmen wir zum Beispiel die Mehrfachvererbung - sie wird normalerweise als schwer zu fassen angesehen (für den Benutzer) und daher nicht zur Sprache hinzugefügt (wie das Diamantproblem).
Gibt es etwas in NATURE dem , const
dass ein Problem dar , dass es besser ist für die Sprache , es zu vermeiden? So etwas wie die Entscheidung, ob const
es tief oder flach sein soll (ein const
Container bedeutet, dass ich kein neues Element hinzufügen oder vorhandene Elemente ändern kann; was ist, wenn Elemente vom Referenztyp sind)?
UPDATE : Während ich C # erwähne und damit eine historische Perspektive mache, interessiere ich mich für die Art der möglichen Probleme const
der Sprache.
Dies ist keine Herausforderung für die Sprachen. Bitte ignorieren Sie solche Faktoren wie aktuelle Trends oder Popularität - ich interessiere mich nur für technische Fragen - danke.
quelle
Antworten:
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. Eineint
Variable ist also unveränderlich, und eineref int
Variable ist ein veränderlicher Container fürint
s. Grundsätzlich sind Variablen echte Variablen im mathematischen Sinne (ein unbekannter, aber fester Wert) undref
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 jedochconst
etwas vergessen und später korrigieren, werden Sie in die in der Antwort von @ RobY erwähnte "const poisoning" -Situation geraten, in der dieconst
Änderung im gesamten Code kaskadiert. Wenn diesconst
der Standard wäre, würden Sie sich nichtconst
rückwirkend bewerben . Außerdem führt das Hinzufügen vonconst
ü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 istHello, world!
, wird beim ersten Versuch, den Wert des ersten Knotens abzurufen, einer gelesenchar
und zurückgegebenH
. Danach kehrt esH
ohne weitere Aufrufe weiter zum Lesen einchar
. Ebenso würde der zweite Knoten einen Festchar
ausstdin
Wenn Sie zum ersten Mal versuchen, seinen Wert abzurufen, wird diesese
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 eineStream
Schnittstelle mitconst
Methoden und alle Funktionen, die Sie erwartenconst Streams
. SieCharStream
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 dieconst
Garantien - jetzt können Sie wirklich nicht sicher sein, dass etwas durch seineconst
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, dieconst
Funktionen erwarten . Eine blinde Durchsetzungconst
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, sodassconst
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.
quelle
var
bei Bedarf nur ein Problem hinterlassen - die Tiefe?const
Verweis auf ein Nicht-const
Objekt haben können. Trotzdem glaube ich nicht, dass es Sinn macht, eine flache zu habenconst
. Der springende Punktconst
ist die Garantie, dass Sie das Objekt über diese Referenz nicht ändern können. Sie dürfen nicht umgehen,const
indem Sie eine Nichtreferenz erstellen.const
Warum sollte es also in Ordnung sein, zu umgehen,const
indem Sie die Mitglieder des Objekts mutieren?func foo(const String &s)
und dies ist ein Signal,s
in dem nichts geändert wirdfoo
.null
und Vererbung).Das Hauptproblem ist, dass Programmierer dazu neigen, es nicht ausreichend zu verwenden. Wenn sie also an eine Stelle gelangen, an der es erforderlich ist, oder wenn ein Betreuer später die Konstanten-Korrektheit korrigieren möchte, gibt es einen enormen Welligkeitseffekt. Sie können immer noch einwandfreien unveränderlichen Code schreiben, ohne den
const
Ihr Compiler nicht erzwingen wird, und es wird schwieriger sein, ihn zu optimieren. Einige Leute bevorzugen, dass ihr Compiler ihnen nicht hilft. Ich verstehe diese Leute nicht, aber es gibt viele von ihnen.In funktionalen Sprachen ist so ziemlich alles möglich
const
, und Veränderlichkeit ist die seltene Ausnahme, wenn sie überhaupt zulässig ist. Dies hat mehrere Vorteile, wie zum Beispiel eine einfachere Parallelität und eine einfachere Überlegung des gemeinsam genutzten Zustands. Es ist jedoch gewöhnungsbedürftig, wenn Sie aus einer Sprache mit einer veränderlichen Kultur stammen. Mit anderen Worten, nicht zu wollenconst
ist eine Frage der Menschen, keine technische.quelle
Ich sehe die Nachteile als:
"const-Vergiftung" ist ein Problem, wenn eine Deklaration von const eine vorherige oder folgende Deklaration zwingen kann, const zu verwenden, und dies kann dazu führen, dass die vorherige oder folgende Deklaration const verwendet, usw. Und wenn die const-Vergiftung in eine Klasse in einer Bibliothek fließt dass Sie nicht die Kontrolle haben, dann können Sie an einem schlechten Ort stecken.
Es ist keine absolute Garantie. Es gibt normalerweise Fälle, in denen die Konstante nur die Referenz schützt, die zugrunde liegenden Werte jedoch aus dem einen oder anderen Grund nicht schützen kann. Sogar in C gibt es Randfälle, an die const nicht herankommen kann, was das Versprechen, das const bietet, schwächt.
Im Allgemeinen scheint sich die Stimmung in der Branche von starken Kompilierungszeitgarantien zu entfernen, wie viel Komfort sie Ihnen und mir auch bringen mögen. Deshalb verbringe ich den Nachmittag damit, 66% meiner Codebasis zu berühren, weil ich eine Konstantenvergiftung habe, etwas Python guy hat 10 perfekt funktionierende, gut gestaltete, erprobte und voll funktionsfähige Python-Module herausgeholt. Und er hackte nicht einmal, als er es tat.
Vielleicht stellt sich die Frage, warum ein potenziell umstrittenes Feature, das selbst einige Experten als ambivalent bezeichnen, wenn Sie versuchen, Ihre schicke neue Sprache einzuführen.
EDIT: kurze Antwort, eine neue Sprache hat einen steilen Hügel zur Adoption zu erklimmen. Die Designer müssen sich wirklich genau überlegen, welche Funktionen sie benötigen, um sich durchzusetzen. Nehmen Sie zum Beispiel Go. Google hat einige der tiefsten religiösen Schlachten brutal abgeschnitten, indem es einige Entwürfe im Conan-the-Barbarian-Stil ausgewählt hat, und ich denke tatsächlich, dass die Sprache besser dafür ist, nach dem, was ich gesehen habe.
quelle
int *
wandelbar Zeiger auf veränderbaren Wert,int const *
änderbare Zeiger auf const Wert,int * const
const Zeiger auf veränderbaren Wert,int const * const
const Zeiger auf const Wert.const
), daher halte ich solche "Gründe" für irrelevant (zumindest für diese Frage). Überconst
Vergiftungen - können Sie ein Beispiel geben? Weil AFAIK es der Vorteil ist, übergibt man etwasconst
und es soll bleibenconst
.const
Problem, aber die Art wirklich zu ändern - was auch immer Sie tun, es wird immer ein Problem sein. Überlegen SieRichString
, ob Sie passen möchten , und stellen Sie dann fest, dass Sie besser passenString
.const
. Es ist zu einfach,const
Dinge, die sein sollten, nichtconst
zu tun , weil man sich dafür entscheiden muss, anstatt sich dagegen zu entscheiden.Es gibt einige philosophische Probleme beim Hinzufügen
const
zu einer Sprache. Wenn Sieconst
eine Klasse deklarieren , bedeutet dies, dass sich die Klasse nicht ändern kann. Eine Klasse ist jedoch eine Reihe von Variablen, die mit Methoden (oder Mutatoren) gekoppelt sind. Wir erreichen die Abstraktion, indem wir den Zustand einer Klasse hinter einer Reihe von Methoden verbergen. Wenn eine Klasse so konzipiert ist, dass sie den Status verbirgt, benötigen Sie Mutatoren, um diesen Status von außen zu ändern, und dann ist er nichtconst
mehr vorhanden. Es ist also nur möglich,const
Klassen zu deklarieren , die unveränderlich sind. Soconst
scheint nur in Szenarien , in denen die Klassen (oder die Typen , die Sie erklären mögenconst
) trivial sind ...Also brauchen wir
const
sowieso? Ich glaube nicht. Ich denke, dass Sie leicht verzichten können,const
wenn Sie ein gutes Design haben. Welche Daten benötigen Sie und wo? Welche Methoden sind Daten-zu-Daten-Methoden? Welche Abstraktionen benötigen Sie für E / A, Netzwerk, Ansicht usw.? unveränderliche Klassen, die keinen Zustand benötigen.Ich denke, die meisten Probleme treten bei großen, fetten Datenobjekten auf, die sich selbst speichern, transformieren und zeichnen können. Dann möchten Sie sie beispielsweise an einen Renderer übergeben. Sie können also den Inhalt der Daten nicht kopieren, da dies für ein großes Datenobjekt zu teuer ist. Aber du willst auch nicht, dass es sich ändert, also brauchst du etwas, wie
const
du denkst. Lassen Sie den Compiler Ihre Designfehler herausfinden. Wenn Sie diese Objekte jedoch nur in ein unveränderliches Datenobjekt aufteilen und die Methoden im verantwortlichen Modul implementieren, können Sie (nur) den Zeiger übergeben und die gewünschten Aktionen mit den Daten ausführen, während gleichzeitig die Unveränderlichkeit gewährleistet ist.Ich weiß, dass es in C ++ möglich ist, einige Methoden
const
zu deklarieren und andere Methoden nicht zu deklarieren, weil sie Mutatoren sind. Und dann einige Zeit später brauchen Sie einen Cache und dann mutiert ein Getter ein Objekt (weil es faul lädt) und es ist nichtconst
mehr. Aber das war der springende Punkt dieser Abstraktion, oder? Sie wissen nicht, welcher Status bei jedem Aufruf geändert wird.quelle
const
(im Sinne von C ++) eingeben möchten ) müssen Sie die Schnittstelle definieren, auch für alle Eigenschaften.