Sogar Sprachen, in denen Sie explizite Zeiger-Manipulationen wie C durchführen, werden immer als Wert übergeben (Sie können sie als Referenz übergeben, aber das ist nicht das Standardverhalten).
Was ist der Vorteil davon, warum werden so viele Sprachen von Werten und warum werden andere als Referenz weitergegeben ? (Ich verstehe, dass Haskell als Referenz übergeben wird, obwohl ich nicht sicher bin).
programming-languages
language-design
Mein Code hat keine Fehler
quelle
quelle
void acceptEntireProgrammingLanguageByValue(C++);
temp := a; a := b; b := temp;
Und wenn sie zurückkehrt, werden die Werte vona
undb
ausgetauscht. In C gibt es keine Möglichkeit, dies zu tun. Sie müssen Zeiger ana
und übergeben,b
und dieswap
Routine muss auf die Werte reagieren, auf die sie zeigen.Antworten:
Wertübergabe ist häufig sicherer als Referenzübergabe, da Sie die Parameter nicht versehentlich an Ihrer Methode / Funktion ändern können. Dies vereinfacht die Verwendung der Sprache, da Sie sich nicht um die Variablen kümmern müssen, die Sie einer Funktion zuweisen. Sie wissen, dass sie nicht geändert werden, und dies ist oft das, was Sie erwarten .
Wenn Sie jedoch die Parameter ändern möchten , müssen Sie eine explizite Operation ausführen, um dies zu verdeutlichen (übergeben Sie einen Zeiger). Dies zwingt alle Ihre Anrufer, den Anruf etwas anders zu tätigen (
&variable
in C), und dies macht deutlich, dass der variable Parameter geändert werden kann.Nun können Sie davon ausgehen, dass eine Funktion Ihren Variablenparameter nicht ändert, es sei denn, dies ist ausdrücklich markiert (indem Sie einen Zeiger übergeben müssen). Dies ist eine sicherere und sauberere Lösung als die Alternative: Nehmen Sie an, dass alles Ihre Parameter ändern kann, es sei denn, sie geben ausdrücklich an, dass dies nicht möglich ist.
quelle
Call-by-Value und Call-by-Reference sind Implementierungstechniken, die vor langer Zeit für Parameterübergabemodi gehalten wurden.
Am Anfang war FORTRAN. FORTRAN hatte nur Call-by-Reference, da Subroutinen in der Lage sein mussten, ihre Parameter zu ändern, und Rechenzyklen zu teuer waren, um mehrere Parameterübergabemodi zuzulassen. Außerdem war nicht genug über die Programmierung bekannt, als FORTRAN zum ersten Mal definiert wurde.
ALGOL hat Call-by-Name und Call-by-Value erfunden. Call-by-Value war für Dinge, die nicht geändert werden sollten (Eingabeparameter). Call-by-Name war für Ausgabeparameter. Call-by-Name stellte sich als großes Problem heraus, und ALGOL 68 ließ es fallen.
PASCAL lieferte Call-by-Value und Call-by-Reference. Es gab dem Programmierer keine Möglichkeit, dem Compiler per Referenz mitzuteilen, dass er ein großes Objekt (normalerweise ein Array) übergeben hat, um zu vermeiden, dass der Parameterstapel aufgeblasen wird, aber das Objekt sollte nicht geändert werden.
PASCAL fügte dem Sprachdesign-Lexikon Zeiger hinzu.
C lieferte Call-by-Value und simulierte Call-by-Reference, indem ein Kludge-Operator definiert wurde, der einen Zeiger auf ein beliebiges Objekt im Speicher zurückgibt.
Spätere Sprachen kopierten C, hauptsächlich, weil die Designer noch nie etwas anderes gesehen hatten. Dies ist wahrscheinlich der Grund, warum Call-by-Value so beliebt ist.
C ++ fügte einen Kludge über dem C-Kludge hinzu, um Call-by-Reference bereitzustellen.
Jetzt haben C und C ++ (Programmierer) als direkte Folge von call-by-value vs. call-by-reference vs. call-by-pointer-kludge schreckliche Kopfschmerzen mit const-Zeigern und Zeigern auf const (schreibgeschützt) Objekte.
Ada hat es geschafft, diesen ganzen Albtraum zu vermeiden.
Ada hat kein explizites Call-by-Value im Vergleich zu Call-by-Reference. Vielmehr hat Ada In-Parameter (die gelesen, aber nicht geschrieben werden können), Out-Parameter (die geschrieben werden MÜSSEN, bevor sie gelesen werden können) und In-Out-Parameter, die in beliebiger Reihenfolge gelesen und geschrieben werden können. Der Compiler entscheidet, ob ein bestimmter Parameter als Wert oder als Referenz übergeben wird: Er ist für den Programmierer transparent.
quelle
In the beginning, there was FORTRAN
.0
Präfix nicht mit jedem anderen Präfix übereinstimmt , das nicht zur Basis 10 gehört. Das mag in C (und meist quellkompatiblen Sprachen, z. B. C ++, Objective C) etwas zu entschuldigen sein, wenn Oktal die einzige alternative Basis bei der Einführung war, aber wenn modernere Sprachen beide0x
und0
von Anfang an verwenden, lassen sie sie nur schlecht aussehen durchdacht.Die Verwendung von Referenzdaten ermöglicht sehr subtile, unbeabsichtigte Nebenwirkungen, die kaum zu ermitteln sind, wenn sie das unbeabsichtigte Verhalten hervorrufen.
Vorbei an Wert, vor allem
final
,static
oderconst
Eingabeparametern machen diese ganze Klasse von Bugs verschwinden.Unveränderliche Sprachen sind noch deterministischer und leichter zu überlegen und zu verstehen, was in einer Funktion vor sich geht und was voraussichtlich daraus resultiert.
quelle
Swap
Hacks, die keine temporäre Variable verwenden, obwohl sie selbst wahrscheinlich kein Problem darstellen, zeigen, wie schwierig das Debuggen eines komplexeren Beispiels sein kann.Wenn Sie große Programme in kleine Unterprogramme aufteilen, können Sie die Unterprogramme unabhängig voneinander beurteilen. Durch die Referenzübergabe wird diese Eigenschaft aufgehoben. (Wie geteilter veränderlicher Zustand.)
Tatsächlich ist C immer ein Übergabewert, niemals ein Übergabewert. Sie können eine Adresse von etwas nehmen und diese Adresse übergeben, aber die Adresse wird weiterhin als Wert übergeben.
Es gibt zwei Hauptgründe für die Verwendung der Referenzübergabe:
Persönlich denke ich, dass # 1 falsch ist: Es ist fast immer eine Entschuldigung für schlechtes API- und / oder Sprachdesign:
Sie können auch mehrere Rückgabewerte simulieren, indem Sie sie in eine einfache Datenstruktur wie ein Tupel packen. Dies funktioniert besonders gut, wenn die Sprache Pattern Matching oder Destructuring Bind unterstützt. ZB Ruby:
Oftmals benötigen Sie nicht einmal mehrere Rückgabewerte. Ein bekanntes Muster ist beispielsweise, dass die Subroutine einen Fehlercode zurückgibt und das tatsächliche Ergebnis als Referenz zurückgeschrieben wird. Stattdessen sollten Sie nur eine Ausnahme auslösen, wenn der Fehler unerwartet ist, oder eine zurückgeben,
Either<Exception, T>
wenn der Fehler erwartet wird. Ein weiteres Muster besteht darin, einen Booleschen Wert zurückzugeben, der angibt, ob die Operation erfolgreich war, und das tatsächliche Ergebnis als Referenz zurückzugeben. Wenn der Fehler unerwartet ist, sollten Sie stattdessen eine Ausnahme auslösen. Wenn der Fehler erwartet wird, z. B. wenn Sie einen Wert in einem Wörterbuch suchen, sollten SieMaybe<T>
stattdessen eine zurückgeben.Referenzübergabe ist möglicherweise effizienter als Wertübergabe, da Sie den Wert nicht kopieren müssen.
Nein, Haskell wird nicht als Referenz übergeben. Es ist auch kein Pass-by-Value. Referenzübergabe und Wertübergabe sind beide strenge Bewertungsstrategien, aber Haskell ist nicht strikt.
Tatsächlich legt die Haskell-Spezifikation keine bestimmte Bewertungsstrategie fest. Die meisten Hakell-Implementierungen verwenden eine Mischung aus Call-by-Name und Call-by-Need (eine Variante von Call-by-Name mit Memoization), der Standard schreibt dies jedoch nicht vor.
Beachten Sie, dass es auch für strenge Sprachen keinen Sinn macht, zwischen Referenzübergabe und Wertübergabe für funktionale Sprachen zu unterscheiden, da der Unterschied zwischen ihnen nur beobachtet werden kann, wenn Sie die Referenz ändern. Daher kann der Implementierer frei zwischen den beiden wählen, ohne die Semantik der Sprache zu brechen.
quelle
Abhängig vom aufrufenden Modell der Sprache, der Art der Argumente und den Speichermodellen der Sprache gibt es ein unterschiedliches Verhalten.
Bei einfachen systemeigenen Typen können Sie den Wert durch Übergeben von Werten an die Register übergeben. Das kann sehr schnell gehen, da der Wert weder aus dem Speicher geladen noch zurückgespeichert werden muss. Eine ähnliche Optimierung ist auch möglich, indem der von dem Argument verwendete Speicher einfach wiederverwendet wird, sobald der Angerufene damit fertig ist, ohne das Risiko einzugehen, die aufrufende Kopie des Objekts zu beschädigen. Wenn das Argument ein temporäres Objekt wäre, müssten Sie wahrscheinlich eine vollständige Kopie speichern (C ++ 11 macht diese Art der Optimierung mit der neuen Rechtsreferenz und ihrer Verschiebungssemantik noch deutlicher).
In vielen OO-Sprachen (C ++ ist in diesem Kontext eher eine Ausnahme) können Sie ein Objekt nicht als Wert übergeben. Sie sind gezwungen, es als Referenz weiterzugeben. Dadurch wird der Code standardmäßig polymorph und entspricht eher dem Begriff der für OO geeigneten Instanzen. Wenn Sie einen Wert angeben möchten, müssen Sie selbst eine Kopie erstellen und dabei die Leistungskosten berücksichtigen, die zu einer solchen Aktion geführt haben. In diesem Fall wählt die Sprache für Sie den Ansatz, mit dem Sie mit größerer Wahrscheinlichkeit die beste Leistung erzielen.
Bei funktionalen Sprachen ist die Weitergabe von Werten oder Referenzen wohl nur eine Frage der Optimierung. Da die Funktionen in einer solchen Sprache rein und so nebenwirkungsfrei sind, gibt es wirklich keinen Grund, den Wert außer der Geschwindigkeit zu kopieren. Ich bin mir sogar ziemlich sicher, dass eine solche Sprache häufig dieselbe Kopie von Objekten mit denselben Werten verwendet, eine Möglichkeit, die nur verfügbar ist, wenn Sie eine (const) -Referenzsemantik verwendet haben. Python verwendete diesen Trick auch für Ganzzahlen und allgemeine Zeichenfolgen (wie Methoden und Klassennamen), um zu erklären, warum Ganzzahlen und Zeichenfolgen in Python konstante Objekte sind. Dies trägt auch dazu bei, den Code erneut zu optimieren, indem beispielsweise ein Zeigervergleich anstelle eines Inhaltsvergleichs möglich ist und einige interne Daten verzögert ausgewertet werden.
quelle
Sie können einen Ausdruck als Wert übergeben, das ist natürlich. Ausdruck als (vorübergehende) Referenz zu übergeben ist ... seltsam.
quelle
Wenn Sie als Referenz übergeben, dann arbeiten Sie effektiv immer mit globalen Werten, mit allen Problemen der globalen Werte (nämlich Umfang und unbeabsichtigte Nebenwirkungen).
Referenzen sind wie globale Referenzen manchmal von Vorteil, sollten aber nicht Ihre erste Wahl sein.
quelle