Dlaczego skróty takie jak x + = y są uważane za dobrą praktykę?


305

Nie mam pojęcia, jak się one faktycznie nazywają, ale cały czas je widzę. Implementacja Pythona wygląda mniej więcej tak:

x += 5jako skrótowy zapis dla x = x + 5.

Ale dlaczego jest to uważane za dobrą praktykę? Natknąłem się na to w prawie każdej książce lub samouczku programowania, który przeczytałem dla Python, C, R i tak dalej. Rozumiem, że to wygodne, oszczędzając trzy naciśnięcia klawiszy, w tym spacje. Ale zawsze wydają mi się denerwować, gdy czytam kod, a przynajmniej w mojej opinii sprawiają, że jest mniej czytelny, a nie więcej.

Czy brakuje mi jasnego i oczywistego powodu, że są one używane wszędzie?


@EricLippert: Czy C # radzi sobie z tym w taki sam sposób, jak opisana najlepsza odpowiedź? Czy faktycznie jest bardziej efektywne pod względem CLR x += 5niż powiedzieć x = x + 5? A może to tak naprawdę cukier syntaktyczny, jak sugerujesz?
blesh

24
@ rozwiązywanie problemów: Te drobne szczegóły dotyczące sposobu wyrażenia dodania w kodzie źródłowym mają wpływ na wydajność wynikowego kodu wykonywalnego, co mogło mieć miejsce w 1970 r .; z pewnością nie jest teraz. Optymalizacja kompilatorów jest dobra i masz większe obawy niż nanosekunda tu czy tam. Idea, że ​​operator + = został opracowany „dwadzieścia lat temu”, jest oczywiście fałszywa; zmarły Dennis Richie opracował C w latach 1969-1973 w Bell Labs.
Eric Lippert,

1
Zobacz blogs.msdn.com/b/ericlippert/archive/2011/03/29/… (patrz także część druga)
SLaks

5
Większość funkcjonalnych programistów rozważy tę złą praktykę.
Pete Kirkham

Odpowiedzi:


598

To nie jest stenografia.

+=Symbol pojawił się w języku C w 1970 roku, a także - z ideą C „inteligentnego asemblerze” odpowiadają wyraźnie inny tryb obsługi maszyn i adresowania:

Rzeczy takie jak „ i=i+1”, "i+=1„i” ++i”, choć na poziomie abstrakcyjnym dają ten sam efekt, na niskim poziomie odpowiadają innym sposobom działania procesora.

W szczególności te trzy wyrażenia, zakładając, że izmienna znajduje się w adresie pamięci przechowywanym w rejestrze procesora (nazwijmy ją D- pomyśl o tym jako o „wskaźniku do int”), a ALU procesora przyjmuje parametr i zwraca wynik w postaci „accumulator” (nazwijmy to A - pomyśl o tym jako int).

Przy tych ograniczeniach (bardzo powszechnych we wszystkich mikroprocesorach z tego okresu) tłumaczenie najprawdopodobniej będzie

;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

Pierwszy sposób na zrobienie tego jest nieoptymalny, ale jest bardziej ogólny, gdy używa się zmiennych zamiast stałej ( ADD A, Blub ADD A, (D+x)) lub tłumaczy bardziej złożone wyrażenia (wszystkie sprowadzają się do operacji push o niskim priorytecie na stosie, nazywają wysoki priorytet, pop i powtarzaj, aż wszystkie argumenty zostaną wyeliminowane).

Drugi jest bardziej typowy dla „automatu stanów”: już nie „oceniamy wyrażenia”, ale „operujemy wartością”: nadal używamy ALU, ale unikamy przesuwania wartości, ponieważ wynik może zastąpić parametr. Tego rodzaju instrukcji nie można stosować tam, gdzie wymagane są bardziej skomplikowane wyrażenia: i = 3*i + i-2nie można ich obsługiwać w miejscu, ponieważ ijest to wymagane więcej razy.

Trzeci - nawet prostszy - nawet nie bierze pod uwagę idei „dodawania”, ale używa bardziej „prymitywnego” (w sensie obliczeniowym) obwodu dla licznika. Instrukcja jest zwarta, ładuje się szybciej i wykonuje się natychmiast, ponieważ sieć kombinatoryczna wymagana do doposażenia rejestru, aby był licznikiem, jest mniejsza, a zatem szybsza niż ta z sumatorem pełnym.

We współczesnych kompilatorach (już teraz C), umożliwiających optymalizację kompilatora, korespondencję można zamieniać w zależności od wygody, ale nadal istnieje koncepcyjna różnica w semantyce.

x += 5 znaczy

  • Znajdź miejsce oznaczone x
  • Dodaj do tego 5

Ale x = x + 5oznacza:

  • Oceń x + 5
    • Znajdź miejsce oznaczone x
    • Skopiuj x do akumulatora
    • Dodaj 5 do akumulatora
  • Zapisz wynik w x
    • Znajdź miejsce oznaczone x
    • Skopiuj do niego akumulator

Oczywiście optymalizacja może

  • jeśli „znalezienie x” nie ma skutków ubocznych, dwa „znalezienie” można wykonać raz (i x stać się adresem zapisanym w rejestrze wskaźnika)
  • dwie kopie można pominąć, jeśli &xzamiast ADD zastosowano akumulator

dzięki czemu zoptymalizowany kod jest zgodny z tym x += 5samym.

Ale można to zrobić tylko wtedy, gdy „znalezienie x” nie ma skutków ubocznych, w przeciwnym razie

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

i

*(x()) += 5;

są semantycznie różne, ponieważ x()efekty uboczne (przyznawanie się x()jest funkcją robienia dziwnych rzeczy i zwracanie an int*) będą wywoływane dwa lub jeden raz.

Równoważność między x = x + yi x += ywynika stąd ze szczególnego przypadku, w którym +=i =są stosowane do bezpośredniej wartości l.

Aby przejść do Pythona, odziedziczył składnię z C, ale ponieważ nie ma tłumaczenia / optymalizacji PRZED wykonaniem w językach interpretowanych, rzeczy niekoniecznie są tak ściśle ze sobą powiązane (ponieważ jest o jeden krok mniej analizy). Jednak interpreter może odwoływać się do różnych procedur wykonywania dla trzech typów wyrażeń, wykorzystując inny kod maszynowy w zależności od sposobu utworzenia wyrażenia i kontekstu oceny.


Dla tych, którzy lubią więcej szczegółów ...

Każdy procesor ma ALU (jednostkę arytmetyczno-logiczną), która w swej istocie jest siecią kombinatoryczną, której wejścia i wyjścia są „podłączane” do rejestrów i / lub pamięci w zależności od kodu operacji instrukcji.

Operacje binarne są zwykle realizowane jako „modyfikator rejestru akumulatorów z wejściem pobranym„ gdzieś ”, gdzie gdzieś może być - wewnątrz samego przepływu instrukcji (typowy dla manifestu: ADD A 5) - wewnątrz innego rejestru (typowy dla obliczeń wyrażeń z tymczasowe: np. ADD AB) - w pamięci, pod adresem podanym przez rejestr (typowe dla pobierania danych, np .: ADD A (H)) - H, w tym przypadku działa jak wskaźnik dereferencji.

Z tym pseudokodem x += 5jest

ADD (X) 5

póki x = x+5jest

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

Oznacza to, że x + 5 daje wartość tymczasową, która jest później przypisywana. x += 5działa bezpośrednio na x.

Rzeczywista implementacja zależy od rzeczywistego zestawu instrukcji procesora: Jeśli nie ma ADD (.) ckodu operacji, pierwszy kod staje się drugim: nie ma mowy.

Jeśli istnieje taki kod operacji, a optymalizacja jest włączona, drugie wyrażenie, po wyeliminowaniu odwrotnych ruchów i dostosowaniu kodu operacji rejestru, staje się pierwszym.


90
+1 za jedyną odpowiedź wyjaśniającą, że w dawnych czasach mapował on inny (i bardziej wydajny) kod maszynowy.
Péter Török,

11
@KeithThompson To prawda, ale nie można zaprzeczyć, że asembler miał ogromny wpływ na projekt języka C (a następnie wszystkich języków w stylu C)
MattDavey

51
Erm, „+ =” nie odwzorowuje na „inc” (odwzorowuje na „dodaj”), „++” odwzorowuje na „inc”.
Brendan

11
Przez „20 lat temu” myślę, że masz na myśli „30 lat temu”. A BTW, COBOL pokonał C przez kolejne 20 lat z: DODAJ 5 DO X.
JoelFan

10
Świetny w teorii; źle w faktach. AS86 INM x86 dodaje tylko 1, więc nie wpływa na omawianego tutaj operatora „dodaj i przypisz” (byłaby to świetna odpowiedź dla „++” i „-”).
Mark Brackett,

281

W zależności od tego, jak o tym myślisz, jest to łatwiejsze do zrozumienia, ponieważ jest prostsze. Weź na przykład:

x = x + 5 wywołuje przetwarzanie w myślach „weź x, dodaj do niego pięć, a następnie przypisz tę nową wartość z powrotem do x”

x += 5 można uznać za „zwiększenie x o 5”

Nie jest to więc tylko skrót, w rzeczywistości opisuje funkcjonalność znacznie bardziej bezpośrednio. Podczas czytania fragmentów kodu łatwiej jest zrozumieć.


32
+1, całkowicie się zgadzam. Jako dziecko zacząłem programować, kiedy mój umysł był łatwo podatny i x = x + 5ciągle mnie niepokoił. Kiedy później zacząłem matematykę, jeszcze bardziej mnie to niepokoiło. Używanie x += 5jest znacznie bardziej opisowe i ma znacznie większy sens jako wyrażenie.
Wielomian

44
Jest też przypadek, w którym zmienna ma długą nazwę: reallyreallyreallylongvariablename = reallyreallyreallylongvariablename + 1... och nie !!! literówka

9
@Matt Fenwick: Nie musi to być długa nazwa zmiennej; może to być pewnego rodzaju wyrażenie. Prawdopodobnie będą one jeszcze trudniejsze do zweryfikowania, a czytelnik musi poświęcić wiele uwagi, aby upewnić się, że są takie same.
David Thornley,

32
X = X + 5 to rodzaj włamania, gdy Twoim celem jest zwiększenie x o 5.
JeffO 10'12

1
@Polynomial Myślę, że jako dziecko natknąłem się na koncepcję x = x + 5. 9 lat, jeśli dobrze pamiętam - i to miało dla mnie doskonały sens i nadal ma dla mnie idealny sens i zdecydowanie wolę to od x + = 5. Pierwszy jest o wiele bardziej szczegółowy i mogę sobie wyobrazić tę koncepcję znacznie jaśniej - pomysł, że przypisuję x, aby była poprzednią wartością x (cokolwiek to jest), a następnie dodaje 5. Myślę, że różne mózgi działają na różne sposoby.
Chris Harrison

48

Przynajmniej w Pythonie , x += ya x = x + ymoże zrobić całkowicie różne rzeczy.

Na przykład, jeśli to zrobimy

a = []
b = a

następnie a += [3]spowoduje a == b == [3], natomiast a = a + [3]spowoduje a == [3]a b == []. Oznacza to, że +=modyfikuje obiekt w miejscu (cóż, może to zrobić, możesz zdefiniować __iadd__metodę wykonywania praktycznie wszystkiego, co chcesz), a jednocześnie =tworzy nowy obiekt i wiąże z nim zmienną.

Jest to bardzo ważne podczas wykonywania pracy numerycznej z NumPy , ponieważ często kończy się to wieloma referencjami do różnych części tablicy, i ważne jest, aby upewnić się, że nie zmodyfikujesz przypadkowo części tablicy, do której istnieją inne odniesienia, lub niepotrzebnie kopiuj tablice (które mogą być bardzo drogie).


4
+1 dla __iadd__: istnieją języki, w którym można utworzyć odwołanie do niezmiennej zmienny datastructure, gdzie operator +=jest zdefiniowana, np scala: val sb = StringBuffer(); lb += "mutable structure"vs var s = ""; s += "mutable variable". tym bardziej modyfikuje zawartość struktury danych, podczas gdy ta ostatnia powoduje, że zmienna wskazuje na nową.
latające owce

43

Nazywa się to idiomem . Idiomy programowania są użyteczne, ponieważ są spójnym sposobem pisania określonej konstrukcji programowania.

Ilekroć ktoś pisze x += y, wiesz, że xjest on zwiększany przez ynie bardziej skomplikowaną operację (jako najlepsza praktyka, zazwyczaj nie mieszałbym bardziej skomplikowanych operacji i tych skrótów składniowych). Ma to największy sens przy zwiększaniu o 1.


13
x ++ i ++ x różnią się nieznacznie od x + = 1 i od siebie.
Gary Willoughby

1
@Gary: ++xi x+=1są równoważne w C i Javie (być może także w C #), choć niekoniecznie w C ++ ze względu na złożoną semantykę operatora. Kluczem jest to, że obaj oceniają xraz, zwiększają zmienną o jeden i uzyskują wynik, który jest zawartością zmiennej po ocenie.
Donal Fellows

3
@Donal Fellows: Priorytet jest inny, więc ++x + 3nie jest taki sam jak x += 1 + 3. Nawiasuj x += 1i jest identyczny. Same wypowiedzi są identyczne.
David Thornley,

1
@DavidThornley: Trudno powiedzieć „są identyczni”, kiedy oboje mają nieokreślone zachowanie :)
Lekkość ściga się na orbicie

1
Żaden z wyrażeń ++x + 3, x += 1 + 3lub (x += 1) + 3mają niezdefiniowane zachowanie (zakładając Uzyskana wartość „leży”).
John Hascall

42

Aby nieco wyjaśnić punkt @ Pubby, zastanów się someObj.foo.bar.func(x, y, z).baz += 5

Bez +=operatora istnieją dwa sposoby:

  1. someObj.foo.bar.func(x, y, z).baz = someObj.foo.bar.func(x, y, z).baz + 5. Jest to nie tylko strasznie zbędne i długie, ale także wolniejsze. Dlatego trzeba by było
  2. Użyć zmiennej czasowej: tmp := someObj.foo.bar.func(x, y, z); tmp.baz = tmp.bar + 5. To jest w porządku, ale jest prosty hałas. To jest naprawdę bardzo zbliżone do tego, co dzieje się w środowisku +=uruchomieniowym , ale pisanie jest uciążliwe, a samo użycie spowoduje przeniesienie pracy do kompilatora / interpretera.

Zalety +=i inne takie podmioty są niezaprzeczalne, a przyzwyczajenie się do nich to tylko kwestia czasu.


Gdy osiągniesz 3 poziomy w głąb łańcucha obiektów, możesz przestać dbać o małe optymalizacje, takie jak 1 i hałaśliwy kod, jak 2. Zamiast tego jeszcze raz zastanów się nad projektem.
Dorus,

4
@Dorus: Wybrane przeze mnie wyrażenie jest po prostu arbitralnym przedstawicielem „złożonego wyrażenia”. Nie krępuj się zastąpić go czymś w głowie, o czym nie będziesz się drażnić;)
back2dos

9
+1: Jest to główny powód tej optymalizacji - zawsze jest poprawny, bez względu na to, jak skomplikowane jest wyrażenie po lewej stronie.
S.Lott,

9
Umieszczenie literówki jest dobrą ilustracją tego, co może się zdarzyć.
David Thornley,

21

To prawda, że ​​jest krótszy i łatwiejszy, i prawdą jest, że prawdopodobnie został zainspirowany podstawowym językiem asemblera, ale najlepszą praktyką jest to, że zapobiega całej klasie błędów i ułatwia przeglądanie kodu i pewność co to robi.

Z

RidiculouslyComplexName += 1;

Ponieważ w grę wchodzi tylko jedna nazwa zmiennej, jesteś pewien, co robi instrukcja.

Z RidiculouslyComplexName = RidiculosulyComplexName + 1;

Zawsze są wątpliwości, że obie strony są dokładnie takie same. Widziałeś błąd? Gorzej, gdy indeksy dolne i kwalifikatory są obecne.


5
Jeszcze gorzej jest w językach, w których instrukcje przypisania mogą domyślnie tworzyć zmienne, szczególnie jeśli w językach rozróżniana jest wielkość liter.
supercat

14

Chociaż notacja + = jest idiomatyczna i krótsza, nie są to powody, dla których łatwiej ją odczytać. Najważniejszą częścią czytania kodu jest mapowanie składni na znaczenie, a więc im bliższa składnia pasuje do procesów myślowych programisty, tym bardziej będzie ona czytelna (jest to również powód, dla którego kod płytki wzorcowej jest zły: nie jest częścią myśli proces, ale nadal konieczne, aby funkcja kodu działała). W tym przypadku chodzi o „zmienną przyrostową x o 5”, a nie „niech x będzie wartością x plus 5”.

Istnieją inne przypadki, w których krótsza notacja jest niekorzystna dla czytelności, na przykład gdy używasz operatora trójskładnikowego, w którym ifinstrukcja byłaby bardziej odpowiednia.


11

Aby dowiedzieć się, dlaczego operatorzy ci posługują się językami w stylu „C”, można znaleźć fragment K&R 1st Edition (1978) 34 lata temu:

Oprócz zwięzłości operatorzy przypisania mają tę zaletę, że lepiej odpowiadają sposobowi myślenia. Mówimy „dodaj 2 do i” lub „zwiększaj i o 2”, „nie” weź i, dodaj 2, a następnie umieść wynik z powrotem w i ”. W ten sposób i += 2. Ponadto, dla skomplikowanego wyrażenia, takiego jak

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

operator przypisania ułatwia zrozumienie kodu, ponieważ czytelnik nie musi dokładnie sprawdzać, czy dwa długie wyrażenia są rzeczywiście takie same, ani zastanawiać się, dlaczego tak nie jest. A operator przypisania może nawet pomóc kompilatorowi w tworzeniu bardziej wydajnego kodu.

Myślę, że z tego fragmentu jasno wynika, że Brian Kernighan i Dennis Ritchie (K&R) wierzyli, że operatorzy przypisań złożonych pomogli w odczytaniu kodu.

Minęło dużo czasu, odkąd K&R to napisał, a wiele „najlepszych praktyk” na temat tego, jak ludzie powinni pisać kod, zmieniło się lub ewoluowało. Ale to pytanie dla programistów.stackexchange po raz pierwszy przypominam sobie kogoś, kto wyraża skargę na czytelność przypisań złożonych, więc zastanawiam się, czy wielu programistów uważa je za problem? Z drugiej strony, kiedy piszę to pytanie, ma 95 głosów pozytywnych, więc może ludzie uważają je za zgrzytliwe podczas czytania kodu.


9

Oprócz czytelności, w rzeczywistości robią różne rzeczy: +=nie muszą dwukrotnie oceniać swojego lewego operandu.

Na przykład expr = expr + 5ewaluowałby exprdwukrotnie (zakładając, że exprjest nieczysty).


Dla wszystkich, oprócz najdziwniejszych kompilatorów, nie ma to znaczenia. Większość kompilatory są wystarczająco inteligentny, aby wygenerować ten sam binarny dla expr = expr + 5iexpr += 5
VSŽ

7
@vsz Nie, jeśli exprma skutki uboczne.
Pubby

6
@vsz: W C, jeśli exprma skutki uboczne, expr = expr + 5 należy wywołać te efekty dwa razy.
Keith Thompson

@Pubby: jeśli ma skutki uboczne, nie ma problemu z „wygodą” i „czytelnością”, co było celem pierwotnego pytania.
vsz

2
Lepiej uważaj na te „skutki uboczne”. Czyta i pisze, że volatilesą skutkami ubocznymi x=x+5i x+=5mają takie same skutki uboczne, kiedy xjestvolatile
MSalters

6

Oprócz oczywistych zalet, które inni opisali bardzo dobrze, kiedy masz bardzo długie nazwiska, jest bardziej zwarty.

  MyVeryVeryVeryVeryVeryLongName += 1;

lub

  MyVeryVeryVeryVeryVeryLongName =  MyVeryVeryVeryVeryVeryLongName + 1;

6

Jest zwięzłe.

Pisanie jest znacznie krótsze. Obejmuje mniej operatorów. Ma mniejszą powierzchnię i mniejszą szansę na zamieszanie.

Korzysta z bardziej konkretnego operatora.

To wymyślony przykład i nie jestem pewien, czy faktyczne kompilatory to implementują. x + = y faktycznie używa jednego argumentu i jednego operatora i modyfikuje x w miejscu. x = x + y może mieć pośrednią reprezentację x = z, gdzie z oznacza x + y. Ten ostatni używa dwóch operatorów, dodawania i przypisania oraz zmiennej tymczasowej. Pojedynczy operator wyjaśnia, że ​​strona wartości nie może być niczym innym niż y i nie musi być interpretowana. I teoretycznie może istnieć jakiś fantazyjny procesor, który ma operator plus-equals, który działa szybciej niż operator plus i operator przypisania szeregowo.


2
Teoretycznie schmeoretycznie. Te ADDinstrukcje na wielu procesorach mieć warianty, które działają bezpośrednio na rejestrach lub pamięci z wykorzystaniem innych rejestrów, pamięci lub stałe jako drugi Dobudowa. Nie wszystkie kombinacje są dostępne (np. Dodaj pamięć do pamięci), ale wystarczy, aby być użytecznym. W każdym razie każdy kompilator z przyzwoitym optymalizatorem będzie wiedział, jak wygenerować taki sam kod, x = x + yjak by to zrobił x += y.
Blrfl,

Stąd „wymyślony”.
Mark Canlas

5

To miły idiom. To, czy jest szybsze, czy nie, zależy od języka. W C jest to szybsze, ponieważ przekłada się na instrukcję zwiększenia zmiennej po prawej stronie. Nowoczesne języki, w tym Python, Ruby, C, C ++ i Java, wszystkie obsługują składnię op =. Jest kompaktowy i szybko się przyzwyczajasz. Ponieważ zobaczysz go bardzo często w kodzie innych osób (OPC), możesz równie dobrze się do niego przyzwyczaić i go używać. Oto, co dzieje się w kilku innych językach.

W Pythonie pisanie x += 5nadal powoduje utworzenie obiektu liczb całkowitych 1 (chociaż można go wyciągnąć z puli) i osierocenie obiektu liczb całkowitych zawierających 5.

W Javie powoduje ukrytą rzutowanie. Spróbuj pisać

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.

Współczesne języki imperatywne . W (czystych) językach funkcjonalnych x+=5ma tak małe znaczenie jak x=x+5; na przykład w Haskell ten ostatni nie powoduje xzwiększenia o 5 - zamiast tego powoduje nieskończoną pętlę rekurencyjną. Kto by tego chciał?
leftaroundabout

Nowoczesne kompilatory niekoniecznie są szybsze: nawet w C.
HörmannHH

Szybkość +=zależy nie tyle od języka, ile od procesora . Na przykład X86 jest architekturą dwóch adresów, obsługuje tylko +=natywnie. Instrukcja taka a = b + c;musi zostać skompilowana, a = b; a += c;ponieważ po prostu nie ma instrukcji, która umieściłaby wynik dodania w innym miejscu niż miejsce jednego z zestawień. Natomiast architektura Power jest architekturą z trzema adresami, dla której nie ma specjalnych poleceń +=. W tej architekturze instrukcje a += b;i a = a + b;zawsze kompilują się do tego samego kodu.
cmaster

4

Operatory, takie jak, +=są bardzo przydatne, gdy używasz zmiennej jako akumulatora , tj. Bieżącej sumy:

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

Jest o wiele łatwiejszy do odczytania niż:

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

W pierwszym przypadku koncepcyjnie modyfikujesz wartość w x. W drugim przypadku obliczasz nową wartość i przypisujesz ją xkażdorazowo. I chociaż prawdopodobnie nigdy nie napisałbyś tak prostego kodu, pomysł pozostaje ten sam ... nacisk kładziony jest na to, co robisz, na istniejącą wartość zamiast tworzenia nowej wartości.


Dla mnie jest dokładnie odwrotnie - pierwszy wariant jest jak brud na ekranie, a drugi jest czysty i czytelny.
Michaił V

1
Różne pociągnięcia dla różnych ludzi, @MikhailV, ale jeśli dopiero zaczynasz programować, możesz po pewnym czasie zmienić swój pogląd.
Caleb

Nie jestem nowy w programowaniu, myślę, że po prostu przyzwyczaiłeś się do + = notacji przez długi czas i dlatego możesz ją przeczytać. Co początkowo nie czyni z niego żadnej dobrze wyglądającej składni, więc operator + otoczony spacjami jest obiektywnie czystszy niż + = i znajomi, których ledwo można odróżnić. Nie chodzi o to, że twoja odpowiedź jest niepoprawna, ale nie należy zbytnio polegać na własnym nawyku sprawiającym, że konsumpcja jest „łatwa do odczytania”.
Michaił V

Mam wrażenie, że bardziej chodzi o konceptualną różnicę między gromadzeniem a przechowywaniem nowych wartości, niż o zwięzłość wyrażenia. Większość imperatywnych języków programowania ma podobne operatory, więc nie jestem jedynym, który uważa je za przydatne. Ale tak jak powiedziałem, różne uderzenia dla różnych ludzi. Nie używaj go, jeśli ci się nie podoba. Jeśli chcesz kontynuować dyskusję, być może bardziej odpowiedni byłby Software Engineering Chat .
Caleb

1

Rozważ to

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

D0 naprawdę chcesz pisać

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

1

Inne odpowiedzi dotyczą bardziej powszechnych przypadków, ale jest też inny powód: w niektórych językach programowania może być przeciążony; np . Scala .


Mała lekcja Scala:

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

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

Jeśli klasa definiuje tylko +operator, x+=yto rzeczywiście jest skrótem od x=x+y.

Jeśli klasa zostanie przeciążona +=, nie są to:

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)”."

Dodatkowo operatory +i +=są dwoma oddzielnymi operatorami (i nie tylko: + a, ++ a, a ++, a + ba + = b są również różnymi operatorami); w językach, w których dostępne jest przeciążenie operatora, może to powodować interesujące sytuacje. Tak jak opisano powyżej - jeśli przeciążasz +operatora, aby wykonać dodawanie, pamiętaj, że również +=będzie to konieczne.


„Jeśli klasa definiuje tylko operator +, x + = y jest rzeczywiście skrótem od x = x + y.” Ale z pewnością działa to również na odwrót? W C ++ bardzo często definiuje się najpierw, +=a następnie definiuje a+bjako „wykonaj kopię a, włóż bją za pomocą +=, zwróć kopię a”.
leftaroundabout

1

Powiedz to raz i tylko raz: w x = x + 1, mówię dwa razy „x”.

Ale nigdy nie pisz: „a = b + = 1”, inaczej będziemy musieli zabić 10 kociąt, 27 myszy, psa i chomika.


Nigdy nie powinieneś zmieniać wartości zmiennej, ponieważ ułatwia to udowodnienie poprawności kodu - patrz programowanie funkcjonalne. Jednak jeśli to zrobisz, lepiej nie mówić rzeczy tylko raz.


„nigdy nie zmieniaj wartości zmiennej” Paradygmat funkcjonalny ?
Peter Mortensen,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.