Przeciążanie operatorów w C ++ jest przez wielu uważane za złą rzecz (tm) i błąd, który nie powinien być powtarzany w nowszych językach. Z pewnością była to jedna z funkcji, która została specjalnie usunięta podczas projektowania języka Java.
Teraz, gdy zacząłem czytać w Scali, stwierdziłem, że wygląda to bardzo podobnie do przeciążenia operatorów (chociaż technicznie nie ma przeciążenia operatorów, ponieważ nie ma operatorów, tylko funkcje). Jednak jakościowo nie wyglądałoby to inaczej niż przeciążenie operatora w C ++, gdzie, jak pamiętam, operatory są definiowane jako funkcje specjalne.
Więc moje pytanie brzmi: co sprawia, że pomysł zdefiniowania „+” w Scali jest lepszym pomysłem niż w C ++?
c++
scala
operator-overloading
skaffman
źródło
źródło
Odpowiedzi:
C ++ dziedziczy prawdziwe niebieskie operatory z C. Rozumiem przez to, że „+” w 6 + 4 jest bardzo szczególne. Nie możesz na przykład pobrać wskaźnika do tej + funkcji.
Z drugiej strony Scala nie ma operatorów w ten sposób. Ma po prostu dużą elastyczność w definiowaniu nazw metod oraz trochę wbudowanego pierwszeństwa dla symboli niebędących słowami. Więc technicznie Scala nie ma przeciążenia operatora.
Jakkolwiek chcesz to nazwać, przeciążenie operatorów nie jest z natury złe, nawet w C ++. Problem polega na tym, że nadużywają go źli programiści. Ale szczerze mówiąc, jestem zdania, że odebranie programistom możliwości nadużywania przeciążenia operatorów nie jest kroplą w morzu w naprawianiu wszystkich rzeczy, które programiści mogą nadużywać. Prawdziwą odpowiedzią jest mentoring. http://james-iry.blogspot.com/2009/03/operator-overloading-ad-absurdum.html
Niemniej jednak istnieją różnice między przeciążeniem operatorów C ++ a elastycznym nazewnictwem metod Scali, które, IMHO, sprawiają, że Scala jest zarówno mniej nadużywalna, jak i bardziej nadużywalna.
W C ++ jedynym sposobem uzyskania notacji w poprawkach jest użycie operatorów. W przeciwnym razie musisz użyć obiektu.message (argument) lub pointer-> messsage (argument) lub funkcji (argument1, argument2). Więc jeśli chcesz mieć określony styl DSLish w swoim kodzie, istnieje presja, aby używać operatorów.
W Scali możesz otrzymać notację wrostkową z każdą wysłaną wiadomością. "argument obiektu wiadomości" jest całkowicie w porządku, co oznacza, że nie musisz używać symboli innych niż słowo, aby uzyskać notację wrostkową.
Przeciążanie operatorów C ++ jest ograniczone zasadniczo do operatorów C. W połączeniu z ograniczeniem polegającym na tym, że tylko operatory mogą być używane wrostek, który wywiera presję na ludziach, aby próbowali odwzorować szeroki zakres niepowiązanych pojęć na stosunkowo nieliczne symbole, takie jak „+” i „>>”
Scala dopuszcza szeroką gamę ważnych symboli niebędących słowami jako nazw metod. Na przykład mam wbudowane DSL w Prologu, w którym możesz pisać
Symbole: -,!,? I & są zdefiniowane jako zwykłe metody. Tylko w C ++ & byłby ważny, więc próba odwzorowania tego DSL na C ++ wymagałaby pewnych symboli, które już wywołują bardzo różne koncepcje.
Oczywiście otwiera to również Scalę na inny rodzaj nadużyć. W Scali możesz nazwać metodę $! & ^%, Jeśli chcesz.
W przypadku innych języków, które, tak jak Scala, są elastyczne w używaniu funkcji niebędących słowami i nazw metod, zobacz Smalltalk, gdzie, podobnie jak Scala, każdy "operator" jest tylko inną metodą i Haskell, który pozwala programiście definiować pierwszeństwo i stałość elastycznie nazwanych Funkcje.
źródło
int main() {return (3).operator+(5);}
Wyniki @Joshuaerror: request for member ‘operator+’ in ‘3’, which is of non-class type ‘int’
Tylko przez ignorantów. Jest to absolutnie wymagane w języku takim jak C ++ i można zauważyć, że inne języki, które zaczęły przyjmować „purystyczny” pogląd, dodały go, gdy ich projektanci dowiedzieli się, jak jest to potrzebne.
źródło
Przeciążanie operatorów nigdy nie było powszechnie uważane za zły pomysł w C ++ - po prostu nadużywanie przeciążania operatorów było uważane za zły pomysł. Tak naprawdę nie trzeba przeciążać operatorów w języku, ponieważ i tak można je symulować za pomocą bardziej szczegółowych wywołań funkcji. Unikanie przeciążania operatorów w Javie sprawiło, że implementacja i specyfikacja Javy stała się nieco prostsza i zmusiła programistów do nie nadużywania operatorów. W społeczności Java odbyła się debata na temat wprowadzenia przeciążenia operatorów.
Zalety i wady przeciążania operatorów w Scali są takie same jak w C ++ - możesz napisać bardziej naturalny kod, jeśli odpowiednio użyjesz przeciążania operatorów - i bardziej tajemniczy, zaciemniony kod, jeśli tego nie zrobisz.
FYI: Operatory nie są zdefiniowane jako funkcje specjalne w C ++, zachowują się tak jak każda inna funkcja - chociaż istnieją pewne różnice w wyszukiwaniu nazw, czy muszą być funkcjami składowymi oraz fakt, że można je wywołać na dwa sposoby: 1 ) składnia operatora i 2) składnia identyfikatora funkcji operatora.
źródło
add(2, multiply(5, 3))
?Ten artykuł - „ Pozytywne dziedzictwo C ++ i Javy ” - odpowiada bezpośrednio na Twoje pytanie.
Java omyłkowo (zdaniem autora) pominęła przeciążenie operatorów, ponieważ w C ++ było to skomplikowane, ale zapomniała dlaczego (lub nie zdawała sobie sprawy, że nie dotyczy to Javy).
Na szczęście języki wyższego poziomu, takie jak Scala, dają programistom opcje, a jednocześnie działają na tej samej JVM.
źródło
Nie ma nic złego w przeciążaniu operatora. W rzeczywistości, jest coś nie tak z nie mając operatora przeciążenia dla typów numerycznych. (Spójrz na kod Java, który używa BigInteger i BigDecimal.)
C ++ ma jednak tradycję nadużywania tej funkcji. Często cytowanym przykładem jest to, że operatorzy bitshift są przeciążeni, aby wykonywać operacje we / wy.
źródło
=
zamiast<<
i>>
we wczesnych dniach C ++, ale napotkałem problemy, ponieważ nie miał on odpowiedniego pierwszeństwa operatora (tj. Czy szuka argumenty najpierw po lewej lub prawej stronie). Więc jego ręce były trochę związane z tym, czego mógłby użyć.Ogólnie nie jest to zła rzecz.
Nowe języki, takie jak C #, również mają przeciążanie operatorów.
To nadużycie przeciążenia operatora jest złą rzeczą.
Ale są też problemy z przeciążaniem operatorów, jak zdefiniowano w C ++. Ponieważ przeciążone operatory są po prostu lukrem składniowym dla wywołań metod, zachowują się tak samo jak metoda. Z drugiej strony normalne operatory wbudowane nie zachowują się jak metody. Ta niespójność może powodować problemy.
Na szczycie mojej głowy operatorzy
||
i&&
.Wbudowane ich wersje to operatory skrótów. Nie dotyczy to wersji przeciążonych i spowodowało pewne problemy.
Fakt, że + - * / all zwracają ten sam typ na którym działają (po promocji operatora)
Przeciążone wersje mogą zwrócić cokolwiek (tu pojawia się nadużycie, Jeśli twoi operatorzy zaczną zwracać jakiś typ arbitra którego użytkownik się nie spodziewał rzeczy idą w dół).
źródło
Przeciążanie operatora nie jest czymś, czego naprawdę "potrzebujesz" bardzo często, ale jeśli używasz Javy, jeśli trafisz w punkt, w którym naprawdę tego potrzebujesz, spowoduje to, że będziesz chciał wyrwać sobie paznokcie, aby mieć wymówkę, aby przestać pisać .
Ten kod, który właśnie znalazłeś, przepełnia się przez długi czas? Tak, będziesz musiał ponownie wpisać wszystko, aby działało z BigInteger. Nie ma nic bardziej frustrującego niż wymyślanie na nowo koła tylko po to, aby zmienić typ zmiennej.
źródło
Guy Steele argumentował, że przeciążanie operatorów powinno być również w Javie, w swoim przemówieniu zatytułowanym „Uprawianie języka” - jest tam wideo i transkrypcja tego, i to naprawdę niesamowita przemowa. Będziesz się zastanawiać, o czym on mówi przez kilka pierwszych stron, ale jeśli będziesz czytać dalej, dostrzeżesz sens i osiągniesz oświecenie. I sam fakt, że w ogóle mógł wygłosić takie przemówienie, jest również niesamowity.
Jednocześnie wykład ten zainspirował wiele podstawowych badań, prawdopodobnie w tym Scalę - to jeden z tych artykułów, które każdy powinien przeczytać, aby pracować w terenie.
Wracając do rzeczy, jego przykłady dotyczą głównie klas numerycznych (takich jak BigInteger i inne dziwne rzeczy), ale to nie jest konieczne.
Prawdą jest jednak, że niewłaściwe użycie przeciążenia operatorów może prowadzić do strasznych rezultatów, a nawet właściwe użycie może skomplikować sprawę, jeśli spróbujesz czytać kod bez odrobiny studiowania bibliotek, z których korzysta. Ale czy to dobry pomysł? OTOH, czy takie biblioteki nie powinny próbować dołączać ściągawki dla swoich operatorów?
źródło
Wierzę, że KAŻDA odpowiedź to pominęła. W C ++ możesz przeciążać operatory, ile chcesz, ale nie możesz wpływać na pierwszeństwo, z jakim są oceniane. Scala nie ma tego problemu, IIRC.
Co do tego, że to zły pomysł, poza kwestiami pierwszeństwa, ludzie wymyślają naprawdę głupie znaczenia dla operatorów i rzadko poprawia to czytelność. Biblioteki Scala są szczególnie złe pod tym względem, głupkowate symbole, które musisz zapamiętywać za każdym razem, a opiekunowie bibliotek chowają głowy w piasek i mówią: „trzeba się tego nauczyć tylko raz”. Świetnie, teraz muszę się nauczyć jakiejś „sprytnej” tajemniczej składni autora * liczbę bibliotek, których chcę używać. Nie byłoby tak źle, gdyby istniała konwencja ZAWSZE zapewniająca piśmienną wersję operatorów.
źródło
Przeciążanie operatorów nie było wynalazkiem C ++ - pochodzi z Algol IIRC i nawet Gosling nie twierdzi, że jest to ogólnie zły pomysł.
źródło
Jedyną nieprawidłową rzeczą w C ++ jest brak możliwości przeładowania [] = jako oddzielnego operatora. Może to być trudne do zaimplementowania w kompilatorze C ++ z prawdopodobnie nieoczywistego powodu, ale jest tego warte.
źródło
Jak wskazały inne odpowiedzi; Przeciążanie operatora niekoniecznie jest złe. Co jest złego, gdy jest używany w sposób, który sprawia, że wynikowy kod nie jest oczywisty. Generalnie podczas ich używania trzeba sprawić, by zrobiły najmniej zaskakującą rzecz (posiadanie dzielenia operator + wykonaj spowodowałoby problemy z racjonalnym wykorzystaniem klasy) lub jak mówi Scott Meyers:
Niektórzy ludzie doprowadzili do skrajności przeciążenie operatorów za pomocą rzeczy takich jak boost :: spirit . Na tym poziomie nie masz pojęcia, jak jest zaimplementowany, ale tworzy interesującą składnię, aby zrobić to, co chcesz. Nie jestem pewien, czy to dobrze, czy źle. Wydaje się fajne, ale nie używałem go.
źródło
Nigdy nie widziałem artykułu stwierdzającego, że przeciążanie operatorów C ++ jest złe.
Operatory definiowane przez użytkownika pozwalają na łatwiejszy wyższy poziom ekspresji i użyteczności dla użytkowników języka.
źródło
AFAIK, nie ma nic specjalnego w funkcjach operatora w porównaniu do "normalnych" funkcji składowych. Oczywiście masz tylko określony zestaw operatorów, który możesz przeciążać, ale to nie czyni ich zbyt wyjątkowymi.
źródło