Warum werden Verknüpfungen wie x + = y als gute Praxis angesehen?

305

Ich habe keine Ahnung, wie diese eigentlich heißen, aber ich sehe sie die ganze Zeit. Die Python-Implementierung sieht ungefähr so ​​aus:

x += 5als Kurzschreibweise für x = x + 5.

Aber warum wird dies als gute Praxis angesehen? Ich habe es in fast jedem Buch oder Programmier-Tutorial gelesen, das ich für Python, C, R usw. gelesen habe . Ich verstehe, dass es praktisch ist, drei Tastenanschläge einschließlich Leerzeichen zu sparen. Aber sie scheinen mich immer zu stören, wenn ich Code lese, und zumindest für mich ist es weniger lesbar, nicht mehr.

Fehlt mir ein klarer und offensichtlicher Grund, warum diese überall verwendet werden?

Fomite
quelle
@EricLippert: Behandelt C # dies genauso wie die oben beschriebene Antwort? Ist es tatsächlich effizienter, CLR-weise zu sagen x += 5als x = x + 5? Oder ist es wirklich nur syntaktischer Zucker, wie Sie vorschlagen?
Fleisch
24
@blesh: Dass kleine Details darüber, wie man einen Zusatz im Quellcode ausdrückt, einen Einfluss auf die Effizienz des resultierenden ausführbaren Codes haben, könnte 1970 der Fall gewesen sein. das ist es jetzt bestimmt nicht. Die Optimierung von Compilern ist gut und Sie haben hier oder da größere Sorgen als eine Nanosekunde. Die Vorstellung, dass der Operator + = "vor zwanzig Jahren" entwickelt wurde, ist offensichtlich falsch; Der verstorbene Dennis Richie entwickelte C von 1969 bis 1973 bei Bell Labs.
Eric Lippert
1
Siehe blogs.msdn.com/b/ericlippert/archive/2011/03/29/… (siehe auch Teil 2)
SLaks
5
Die meisten funktionalen Programmierer werden diese schlechte Praxis in Betracht ziehen.
Pete Kirkham

Antworten:

598

Es ist keine Kurzschrift.

Das +=Symbol erschien in den 1970er Jahren in der C-Sprache und - mit der C-Idee "Smart Assembler" korrespondiert es mit einer deutlich anderen Maschinenanweisung und Adressierungsart:

Dinge wie " i=i+1", "i+=1"und" ++i"entsprechen, obwohl sie auf abstrakter Ebene den gleichen Effekt haben, auf niedriger Ebene einer anderen Arbeitsweise des Prozessors.

Insbesondere diese drei Ausdrücke, vorausgesetzt, die iVariable befindet sich in der Speicheradresse, die in einem CPU-Register gespeichert ist (nennen wir es D- betrachten wir es als "Zeiger auf int"), und die ALU des Prozessors nimmt einen Parameter und gibt ein Ergebnis in einem zurück "Akku" (nennen wir es A - denken Sie daran als int).

Mit diesen Einschränkungen (sehr häufig in allen Mikroprozessoren aus dieser Zeit) wird die Übersetzung höchstwahrscheinlich sein

;i = i+1;
MOV A,(D); //Move in A the content of the memory whose address is in D
ADD A, 1;  //The addition of an inlined constant
MOV (D) A; //Move the result back to i (this is the '=' of the expression)

;i+=1;
ADD (D),1; //Add an inlined constant to a memory address stored value

;++i;
INC (D); //Just "tick" a memory located counter

Die erste Möglichkeit ist nicht optimal, sie ist jedoch allgemeiner, wenn Sie mit Variablen anstelle von Konstanten ( ADD A, Boder ADD A, (D+x)) arbeiten oder komplexere Ausdrücke übersetzen (sie laufen alle im Push-Vorgang mit niedriger Priorität in einem Stapel zusammen, nennen Sie die hohe Priorität pop und wiederholen, bis alle Argumente beseitigt sind.

Die zweite ist typischer für "Zustandsmaschine": Wir "evaluieren" nicht länger einen Ausdruck, sondern "operieren einen Wert": Wir verwenden weiterhin die ALU, vermeiden jedoch, dass Werte verschoben werden, damit das Ergebnis den Parameter ersetzen kann. Diese Art von Anweisung kann nicht verwendet werden, wenn kompliziertere Ausdrücke erforderlich sind: i = 3*i + i-2Kann nicht an Ort und Stelle ausgeführt werden, da imehrmals erforderlich.

Die dritte - einfachere - betrachtet nicht einmal die Idee der "Addition", sondern verwendet eine "primitivere" (im rechnerischen Sinne) Schaltung für einen Zähler. Der Befehl ist kurzgeschlossen, wird schneller geladen und sofort ausgeführt, da das kombinatorische Netzwerk, das zum Nachrüsten eines Registers erforderlich ist, um es zu einem Zähler zu machen, kleiner und daher schneller als das eines Volladdierers ist.

Mit modernen Compilern (siehe C), die die Compileroptimierung ermöglichen, kann die Korrespondenz nach Belieben ausgetauscht werden, aber es gibt immer noch einen konzeptionellen Unterschied in der Semantik.

x += 5 meint

  • Suchen Sie den mit x gekennzeichneten Ort
  • Addiere 5 dazu

Aber x = x + 5heißt:

  • Bewerten Sie x + 5
    • Suchen Sie den mit x gekennzeichneten Ort
    • Kopieren Sie x in einen Akku
    • Addiere 5 zum Akku
  • Speichern Sie das Ergebnis in x
    • Suchen Sie den mit x gekennzeichneten Ort
    • Kopieren Sie den Akku darauf

Natürlich kann Optimierung

  • Wenn "x finden" keine Nebenwirkungen hat, können die beiden "Suchen" einmal durchgeführt werden (und x wird zu einer Adresse, die in einem Zeigerregister gespeichert ist).
  • Die zwei Kopien können entfernt werden, wenn der ADD &xstattdessen auf den Akku angewendet wird

Auf diese Weise wird der optimierte Code so gestaltet, dass er mit dem x += 5einen übereinstimmt .

Dies ist jedoch nur möglich, wenn "x finden" keine Nebenwirkungen hat, ansonsten

*(x()) = *(x()) + 5;

und

*(x()) += 5;

sind semantisch unterschiedlich, da x()Nebenwirkungen (zugeben x()ist eine Funktion, die seltsame Dinge tut und zurückgibt int*) zweimal oder einmal auftreten.

Die Äquivalenz zwischen x = x + yund x += yist daher auf den besonderen Fall zurückzuführen, in dem +=und =auf einen direkten l-Wert angewendet werden.

Um auf Python umzusteigen, wurde die Syntax von C übernommen. Da es jedoch keine Übersetzung / Optimierung VOR der Ausführung in interpretierten Sprachen gibt, hängen die Dinge nicht unbedingt so eng zusammen (da es nur einen Analyseschritt weniger gibt). Ein Interpreter kann jedoch auf verschiedene Ausführungsroutinen für die drei Ausdruckstypen verweisen und dabei abhängig von der Art der Ausdrucksbildung und dem Auswertungskontext unterschiedlichen Maschinencode verwenden.


Für diejenigen, die mehr Details mögen ...

Jede CPU hat eine ALU (arithmetisch-logische Einheit), die im Grunde genommen ein kombinatorisches Netzwerk ist, dessen Ein- und Ausgänge in Abhängigkeit vom Operationscode des Befehls mit den Registern und / oder dem Speicher "verbunden" sind.

Binäroperationen werden typischerweise als "Modifikator eines Akkumulatorregisters" implementiert, wobei eine Eingabe "irgendwo" erfolgt, wobei sich irgendwo - innerhalb des Befehlsflusses selbst (typisch für Manifest Contant: ADD A 5) - innerhalb eines anderen Registers befinden kann (typisch für Ausdrucksberechnung mit temporaries (z. B. ADD AB) - innerhalb des Speichers an einer von einem Register vorgegebenen Adresse (typisch für das Abrufen von Daten, z. B. ADD A (H)) - H funktionieren in diesem Fall wie ein Dereferenzierungszeiger.

Mit diesem Pseudocode x += 5ist

ADD (X) 5

während x = x+5ist

MOVE A (X)
ADD A 5
MOVE (X) A

Das heißt, x + 5 gibt ein temporäres Objekt an, das später zugewiesen wird. x += 5arbeitet direkt auf x.

Die tatsächliche Implementierung hängt vom tatsächlichen Befehlssatz des Prozessors ab: Wenn kein ADD (.) cOpcode vorhanden ist , wird der erste Code zum zweiten: no way.

Wenn es einen solchen Opcode gibt und die Optimierung aktiviert ist, wird der zweite Ausdruck nach Eliminierung der Rückwärtsbewegung und Anpassung des Register-Opcodes der erste.

Emilio Garavaglia
quelle
90
+1 für die einzige Antwort, die erklärt, dass sie früher unterschiedlichen (und effizienteren) Maschinencodes zugeordnet war.
Péter Török
11
@KeithThompson Das ist wahr, aber man kann nicht leugnen, dass Assembly einen großen Einfluss auf das Design der C-Sprache (und anschließend aller C-Stil-Sprachen) hatte
MattDavey
51
Ähm, "+ =" entspricht nicht "inc" (es entspricht "add"), "++" entspricht "inc".
Brendan
11
Mit "vor 20 Jahren" meine ich "vor 30 Jahren". Und übrigens, COBOL hatte C um weitere 20 Jahre geschlagen mit: ADD 5 TO X.
JoelFan
10
In der Theorie großartig; falsch in Fakten. Das x86-ASM INC fügt nur 1 hinzu, hat also keinen Einfluss auf den hier beschriebenen Operator "add and assign" (dies wäre jedoch eine großartige Antwort für "++" und "-").
Mark Brackett
281

Je nachdem, wie Sie darüber nachdenken, ist es tatsächlich einfacher zu verstehen, weil es einfacher ist. Nehmen Sie zum Beispiel:

x = x + 5 ruft die mentale Verarbeitung von "nimm x, addiere fünf dazu und ordne dann diesen neuen Wert wieder x zu" auf

x += 5 kann gedacht werden als "x um 5 erhöhen"

Es ist also nicht nur eine Kurzform, sondern beschreibt die Funktionalität direkter. Beim Lesen von Codegegenständen ist es viel einfacher zu verstehen.

Eric King
quelle
32
+1, da stimme ich voll zu. Ich fing als Kind an zu programmieren, als mein Verstand leicht formbar war und x = x + 5mich immer noch beunruhigte. Als ich in einem späteren Alter in die Mathematik kam, störte mich das noch mehr. Verwenden x += 5ist deutlich aussagekräftiger und als Ausdruck viel sinnvoller.
Polynom
44
Es gibt auch den Fall, dass die Variable einen langen Namen hat: reallyreallyreallylongvariablename = reallyreallyreallylongvariablename + 1... oh nein !!! Ein Tippfehler
9
@ Matt Fenwick: Es muss kein langer Variablenname sein. es könnte eine Art Ausdruck sein. Diese sind wahrscheinlich noch schwerer zu überprüfen, und der Leser muss viel Aufmerksamkeit aufwenden, um sicherzustellen, dass sie gleich sind.
David Thornley
32
X = X + 5 ist eine Art Hack, wenn Sie x um 5
erhöhen möchten
1
@Polynomial Ich glaube, ich bin auch als Kind auf das Konzept von x = x + 5 gestoßen. 9 Jahre alt, wenn ich mich recht erinnere - und es machte für mich vollkommen Sinn und es macht für mich jetzt vollkommen Sinn und ist viel lieber für x + = 5. Das erste ist viel ausführlicher und ich kann mir das Konzept viel klarer vorstellen - Die Idee, dass ich x als vorherigen Wert von x zuordne (was auch immer das ist) und dann 5 hinzufüge. Ich denke, dass verschiedene Gehirne auf verschiedene Arten funktionieren.
Chris Harrison
48

Zumindest in Python , x += yund x = x + ykann ganz andere Dinge tun.

Zum Beispiel, wenn wir das tun

a = []
b = a

dann a += [3]ergibt sich a == b == [3], während a = a + [3]ergibt sich a == [3]und b == []. Das heißt, +=Sie können das Objekt direkt ändern (möglicherweise können Sie die __iadd__Methode so definieren, dass Sie so ziemlich alles tun, was Sie möchten), während Sie =ein neues Objekt erstellen und die Variable daran binden.

Dies ist sehr wichtig, wenn Sie mit NumPy numerisch arbeiten , da Sie häufig mehrere Verweise auf verschiedene Teile eines Arrays haben und Sie sicherstellen müssen, dass Sie nicht versehentlich Teile eines Arrays ändern, auf die es andere Verweise gibt. oder unnötigerweise Arrays kopieren (was sehr teuer sein kann).

James
quelle
4
+1 für __iadd__: Es gibt Sprachen, in denen Sie einen unveränderlichen Verweis auf eine veränderbare Datenstruktur erstellen können, in der operator +=die definiert ist, z . B. scala: val sb = StringBuffer(); lb += "mutable structure"vs. var s = ""; s += "mutable variable"Dadurch wird der Inhalt der Datenstruktur weiter geändert, während die Variable auf eine neue verweist.
fliegende Schafe
43

Es heißt eine Redewendung . Programmiersprachen sind nützlich, da sie eine konsistente Methode zum Schreiben eines bestimmten Programmierkonstrukts darstellen.

Wann immer jemand schreibt x += y, wissen Sie, dass die Operation xinkrementiert wird yund keine komplexere Operation (als Best Practice würde ich normalerweise keine komplizierteren Operationen und diese Syntaxkürzel mischen). Dies ist am sinnvollsten, wenn um 1 erhöht wird.

Joe
quelle
13
x ++ und ++ x unterscheiden sich geringfügig von x + = 1 und voneinander.
Gary Willoughby
1
@Gary: ++xund x+=1sind in C und Java (möglicherweise auch C #) äquivalent, jedoch nicht unbedingt in C ++, da dort eine komplexe Operatorsemantik vorliegt. Der Schlüssel ist, dass beide xeinmal auswerten , die Variable um eins inkrementieren und ein Ergebnis erhalten, das der Inhalt der Variablen nach der Auswertung ist.
Donal Fellows
3
@Donal Fellows: Die Rangfolge ist unterschiedlich, ++x + 3ist also nicht gleich x += 1 + 3. Klammern Sie das ein x += 1und es ist identisch. Als Aussagen für sich sind sie identisch.
David Thornley
1
@ DavidThornley: Es ist schwer zu sagen, "sie sind identisch", wenn sie beide undefiniertes Verhalten haben :)
Lightness Races in Orbit
1
Keiner der Ausdrücke ++x + 3, x += 1 + 3oder (x += 1) + 3haben das Verhalten nicht definiert (vorausgesetzt , der sich ergebende Wert „passt“).
John Hascall
42

Um @ Pubby's Punkt etwas klarer zu machen, überlegen Sie sich someObj.foo.bar.func(x, y, z).baz += 5

Ohne den +=Bediener gibt es zwei Möglichkeiten:

  1. someObj.foo.bar.func(x, y, z).baz = someObj.foo.bar.func(x, y, z).baz + 5. Dies ist nicht nur furchtbar redundant und lang, sondern auch langsamer. Deshalb müsste man
  2. Verwenden Sie eine temporäre Variable: tmp := someObj.foo.bar.func(x, y, z); tmp.baz = tmp.bar + 5. Das ist in Ordnung, aber für eine einfache Sache ist es viel Lärm. Dies ist eigentlich sehr ähnlich zu dem, was zur Laufzeit passiert, aber es ist mühsam zu schreiben und nur die Verwendung +=wird die Arbeit auf den Compiler / Interpreter verlagern.

Der Vorteil +=und anderer solcher Operatoren ist unbestreitbar, während es nur eine Frage der Zeit ist, sich an sie zu gewöhnen.

back2dos
quelle
Sobald Sie 3 Ebenen tief in der Objektkette sind, können Sie aufhören, sich um kleine Optimierungen wie 1 und verrauschten Code wie 2 zu kümmern. Denken Sie stattdessen noch einmal über Ihr Design nach.
Dorus
4
@Dorus: Der von mir gewählte Ausdruck ist nur ein willkürlicher Vertreter für "Komplexer Ausdruck". Fühlen Sie sich frei, um es durch etwas in Ihrem Kopf zu ersetzen, dass Sie nicht überpicken werden;)
back2dos
9
+1: Dies ist der Hauptgrund für diese Optimierung - es ist immer richtig, egal wie komplex der Ausdruck auf der linken Seite ist.
S.Lott
9
Wenn Sie einen Tippfehler eingeben, sehen Sie, was passieren kann.
David Thornley
21

Es ist wahr, dass es kürzer und einfacher ist, und es ist wahr, dass es wahrscheinlich von der zugrunde liegenden Assemblersprache inspiriert wurde, aber der Grund für die Best Practice ist, dass es eine ganze Klasse von Fehlern vermeidet und es einfacher macht, den Code zu überprüfen und sicher zu sein Was es macht.

Mit

RidiculouslyComplexName += 1;

Da es sich nur um einen Variablennamen handelt, sind Sie sicher, was die Anweisung bewirkt.

Mit RidiculouslyComplexName = RidiculosulyComplexName + 1;

Es gibt immer Zweifel, dass die beiden Seiten genau gleich sind. Hast du den Bug gesehen? Noch schlimmer wird es, wenn Indizes und Qualifikatoren vorhanden sind.

Jamie Cox
quelle
5
In Sprachen, in denen Zuweisungsanweisungen implizit Variablen erstellen können, wird es noch schlimmer, insbesondere wenn bei den Sprachen zwischen Groß- und Kleinschreibung unterschieden wird.
Supercat
14

Während die + = Notation idiomatisch und kürzer ist, sind dies nicht die Gründe, warum es leichter zu lesen ist. Der wichtigste Teil des Lesens von Code ist die Zuordnung der Syntax zur Bedeutung. Je genauer die Syntax mit den Gedankenprozessen des Programmierers übereinstimmt, desto besser lesbar ist sie (dies ist auch der Grund, warum Boilerplate-Code schlecht ist: Sie ist kein Teil des Gedankens Prozess, aber immer noch notwendig, damit der Code funktioniert). In diesem Fall lautet der Gedanke "Variable x um 5 erhöhen", nicht "x sei der Wert von x plus 5".

In anderen Fällen ist eine kürzere Schreibweise für die Lesbarkeit schlecht, z. B. wenn Sie einen ternären Operator verwenden, bei dem eine ifAnweisung geeigneter wäre.

tdammers
quelle
11

Um zu verstehen, warum diese Operatoren zunächst in den Sprachen des C-Stils abgefasst sind, finden Sie hier einen Auszug aus K & R 1st Edition (1978) vor 34 Jahren:

Zuweisungsoperatoren haben, abgesehen von der Prägnanz, den Vorteil, dass sie besser der Denkweise der Menschen entsprechen. Wir sagen "addiere 2 zu i" oder "erhöhe i um 2", nicht "nimm i, addiere 2, dann setze das Ergebnis zurück in i". Also i += 2. Darüber hinaus für einen komplizierten Ausdruck wie

yyval[yypv[p3+p4] + yypv[p1+p2]] += 2

Der Zuweisungsoperator erleichtert das Verständnis des Codes, da der Leser nicht sorgfältig prüfen muss, ob zwei lange Ausdrücke tatsächlich identisch sind, oder sich fragen muss, warum sie nicht identisch sind. Ein Zuweisungsoperator kann dem Compiler sogar dabei helfen, effizienteren Code zu erstellen.

Ich denke, aus dieser Passage geht hervor, dass Brian Kernighan und Dennis Ritchie (K & R) der Ansicht waren, dass Operatoren für die Zuweisung von Compounds die Lesbarkeit des Codes verbessern.

Es ist lange her, dass K & R das geschrieben hat, und seitdem haben sich viele der „Best Practices“ zum Schreiben von Code geändert oder weiterentwickelt. Mit dieser Frage zu programmers.stackexchange kann ich mich zum ersten Mal an jemanden erinnern, der eine Beschwerde über die Lesbarkeit von zusammengesetzten Zuweisungen geäußert hat. Ich frage mich also, ob viele Programmierer diese als Problem empfinden. Andererseits hat die Frage, während ich dies tippe, 95 positive Stimmen, so dass die Leute sie vielleicht beim Lesen von Code als irritierend empfinden.

Michael Burr
quelle
9

Neben der Lesbarkeit machen sie tatsächlich verschiedene Dinge: Sie +=müssen den linken Operanden nicht zweimal auswerten.

Zum Beispiel expr = expr + 5würde exprzweimal auswerten (vorausgesetzt, exprist unrein).

Pubby
quelle
Für alle außer den seltsamsten Compilern spielt es keine Rolle. Die meisten Compiler sind schlau genug, um dieselbe Binärdatei für expr = expr + 5undexpr += 5
vsz
7
@vsz Nicht wenn exprNebenwirkungen vorliegen .
Pubby
6
@vsz: Wenn in C exprNebenwirkungen auftreten, expr = expr + 5 müssen diese zweimal aufgerufen werden .
Keith Thompson
@Pubby: Wenn es Nebenwirkungen hat, gibt es kein Problem mit "Bequemlichkeit" und "Lesbarkeit", worum es in der ursprünglichen Frage ging.
vsz
2
Passen Sie besser auf diese "Nebenwirkungen" auf. Liest und schreibt an volatileNebenwirkungen sind, und x=x+5und x+=5die gleichen Nebenwirkungen haben , wenn xistvolatile
MSalters
6

Abgesehen von den offensichtlichen Vorteilen, die andere Leute sehr gut beschrieben haben, ist es kompakter, wenn Sie sehr lange Namen haben.

  MyVeryVeryVeryVeryVeryLongName += 1;

oder

  MyVeryVeryVeryVeryVeryLongName =  MyVeryVeryVeryVeryVeryLongName + 1;
Andrey Rubshtein
quelle
6

Es ist prägnant.

Es ist viel kürzer zu tippen. Es sind weniger Bediener beteiligt. Es hat weniger Oberfläche und weniger Verwechslungsgefahr.

Es wird ein spezifischerer Operator verwendet.

Dies ist ein erfundenes Beispiel, und ich bin mir nicht sicher, ob tatsächliche Compiler dies implementieren. x + = y verwendet tatsächlich ein Argument und einen Operator und ändert x an Ort und Stelle. x = x + y könnte eine Zwischendarstellung von x = z haben, wobei z x + y ist. Letzterer verwendet zwei Operatoren, Addition und Zuweisung sowie eine temporäre Variable. Der einzelne Operator macht sehr deutlich, dass die Werteseite nichts anderes als y sein kann und nicht interpretiert werden muss. Und theoretisch könnte es eine ausgefallene CPU geben, die einen Plus-Gleichheitsoperator hat, der schneller läuft als ein Plus-Operator und einen Zuweisungsoperator in Reihe.

Mark Canlas
quelle
2
Theoretisch schmeoretisch. Die ADDAnweisungen auf vielen CPUs haben Varianten, die direkt mit Registern oder Speicher arbeiten, wobei andere Register, Speicher oder Konstanten als zweites Addend verwendet werden. Es sind nicht alle Kombinationen verfügbar (z. B. Speicher zum Speicher hinzufügen), aber es gibt genug, um nützlich zu sein. In jedem Fall wird jeder Compiler mit einem anständigen Optimierer wissen, dass er den gleichen Code x = x + ywie für generiert x += y.
Blrfl
Daher "erfunden".
Mark Canlas
5

Es ist eine schöne Sprache. Ob es schneller geht oder nicht, hängt von der Sprache ab. In C ist es schneller, da es sich um eine Anweisung zum Erhöhen der Variablen auf der rechten Seite handelt. Moderne Sprachen wie Python, Ruby, C, C ++ und Java unterstützen die Syntax op =. Es ist kompakt und man gewöhnt sich schnell daran. Da Sie es häufig im Code anderer Leute (OPC) sehen, können Sie sich auch daran gewöhnen und ihn verwenden. Hier ist, was in einigen anderen Sprachen passiert.

In Python führt das Eingeben x += 5immer noch zur Erstellung des Ganzzahlobjekts 1 (obwohl es möglicherweise aus einem Pool stammt) und zum Verwaisen des Ganzzahlobjekts mit 5.

In Java kommt es zu einer stillschweigenden Umwandlung. Versuchen Sie es mit der Eingabe

int x = 4;
x = x + 5.2  // This causes a compiler error
x += 5.2     // This is not an error; an implicit cast is done.
ncmathsadist
quelle
Moderne imperative Sprachen. In (reinen) funktionalen Sprachen x+=5hat so wenig Bedeutung wie x=x+5; Zum Beispiel in Haskell bewirkt Letzteres nicht, dass xes um 5 inkrementiert wird - stattdessen entsteht eine unendliche Rekursionsschleife. Wer möchte eine Abkürzung dafür?
links ungefähr
Mit modernen Compilern geht es nicht unbedingt schneller: auch in C.
HörmannHH
Die Geschwindigkeit von +=ist weniger sprachabhängig als prozessorabhängig . Beispielsweise ist X86 eine Architektur mit zwei Adressen, die nur +=nativ unterstützt wird. Eine Aussage wie a = b + c;muss kompiliert werden, a = b; a += c;weil es einfach keine Anweisung gibt, die das Ergebnis der Addition irgendwo anders als an die Stelle eines der Summanden setzen kann. Im Gegensatz dazu ist die Power-Architektur eine Architektur mit drei Adressen, für die keine speziellen Befehle vorhanden sind +=. Auf dieser Architektur kompilieren die Anweisungen a += b;und a = a + b;immer den gleichen Code.
CMASTER
4

Operatoren wie +=sind sehr nützlich, wenn Sie eine Variable als Akkumulator verwenden , dh eine laufende Summe:

x += 2;
x += 5;
x -= 3;

Ist viel einfacher zu lesen als:

x = x + 2;
x = x + 5;
x = x - 3;

Im ersten Fall ändern Sie konzeptionell den Wert in x. Im zweiten Fall berechnen Sie einen neuen Wert und weisen ihn xjedem Mal zu. Und während Sie wahrscheinlich niemals Code schreiben würden, der so einfach ist, bleibt die Idee dieselbe ... Der Fokus liegt auf dem, was Sie mit einem vorhandenen Wert tun, anstatt einen neuen Wert zu schaffen.

Caleb
quelle
Für mich ist es genau das Gegenteil - die erste Variante ist wie Schmutz auf dem Bildschirm und die zweite ist sauber und lesbar.
Mikhail V
1
Verschiedene Striche für verschiedene Leute, @MikhailV, aber wenn Sie neu in der Programmierung sind, können Sie Ihre Ansicht nach einer Weile ändern.
Caleb
Ich bin nicht so neu in der Programmierung, ich glaube nur, dass Sie sich über einen langen Zeitraum einfach an die + = Notation gewöhnt haben und sie daher lesen können. Wodurch es anfangs keine gute Syntax gibt, ist ein von Leerzeichen umgebener + Operator objektiv sauberer als + = und Freunde, die alle kaum zu unterscheiden sind. Nicht, dass Ihre Antwort falsch ist, aber man sollte sich nicht zu sehr auf die eigene Angewohnheit verlassen und den Konsum so machen, wie "einfach zu lesen".
Mikhail V
Mein Gefühl ist, dass es mehr um den konzeptionellen Unterschied zwischen dem Akkumulieren und Speichern neuer Werte geht, als darum, den Ausdruck kompakter zu gestalten. Die meisten imperativen Programmiersprachen haben ähnliche Operatoren, daher scheine ich nicht der einzige zu sein, der dies für nützlich hält. Aber wie gesagt, verschiedene Schlaganfälle für verschiedene Leute. Verwenden Sie es nicht, wenn Sie es nicht mögen. Wenn Sie die Diskussion fortsetzen möchten, bietet sich vielleicht der Software Engineering Chat an .
Caleb
1

Bedenken Sie

(some_object[index])->some_other_object[more] += 5

Willst du wirklich schreiben?

(some_object[index])->some_other_object[more] = (some_object[index])->some_other_object[more] + 5
S.Lott
quelle
1

Die anderen Antworten zielen auf die häufigsten Fälle ab, aber es gibt noch einen anderen Grund: In einigen Programmiersprachen kann es zu einer Überlastung kommen. zB Scala .


Kleine Scala-Lektion:

var j = 5 #Creates a variable
j += 4    #Compiles

val i = 5 #Creates a constant
i += 4    #Doesn’t compile

Wenn eine Klasse nur den +Operator definiert , x+=yist das in der Tat eine Abkürzung von x=x+y.

Überladungen einer Klasse +=sind jedoch nicht:

var a = ""
a += "This works. a now points to a new String."

val b = ""
b += "This doesn’t compile, as b cannot be reassigned."

val c = StringBuffer() #implements +=
c += "This works, as StringBuffer implements “+=(c: String)”."

Außerdem sind Operatoren +und +=zwei separate Operatoren (und nicht nur diese: + a, ++ a, a ++, a + ba + = b sind ebenfalls verschiedene Operatoren); In Sprachen, in denen eine Überlastung des Operators vorliegt, kann dies zu interessanten Situationen führen. Genau wie oben beschrieben - wenn Sie den +Operator überlasten , um das Hinzufügen durchzuführen, bedenken Sie, dass +=auch dieser überlastet werden muss.

fliegende Schafe
quelle
"Wenn eine Klasse nur den Operator + definiert, ist x + = y in der Tat eine Abkürzung von x = x + y." Aber es funktioniert doch auch umgekehrt? In C ++ ist es üblich, zuerst zu definieren +=und dann zu definieren a+b, dass "eine Kopie von erstellt a, bmit angelegt +=und die Kopie von zurückgegeben wird a".
Am
1

Sagen Sie es einmal und nur einmal: x = x + 1Ich sage zweimal 'x'.

Aber schreibe niemals 'a = b + = 1', sonst müssen wir 10 Kätzchen, 27 Mäuse, einen Hund und einen Hamster töten.


Sie sollten den Wert einer Variablen niemals ändern, da dies den Nachweis der Code-Korrektheit erleichtert (siehe Funktionsprogrammierung). Wenn Sie dies jedoch tun, ist es besser, nichts nur einmal zu sagen.

richard
quelle
"Niemals den Wert einer Variablen ändern" Funktionsparadigma ?
Peter Mortensen