Das Überladen von Operatoren in C ++ wird von vielen als A Bad Thing (tm) angesehen und als Fehler, der in neueren Sprachen nicht wiederholt werden darf. Sicherlich war es eine Funktion, die speziell beim Entwerfen von Java weggelassen wurde.
Nachdem ich angefangen habe, Scala zu lesen, stelle ich fest, dass es eine Art Operatorüberladung aufweist (obwohl es technisch gesehen keine Operatorüberladung gibt, weil es keine Operatoren, sondern nur Funktionen hat). Es scheint sich jedoch qualitativ nicht von der Operatorüberladung in C ++ zu unterscheiden, bei der Operatoren, wie ich mich erinnere, als Sonderfunktionen definiert sind.
Meine Frage ist also, warum die Idee, "+" in Scala zu definieren, eine bessere Idee ist als in C ++.
c++
scala
operator-overloading
Skaffman
quelle
quelle
Antworten:
C ++ erbt echte blaue Operatoren von C. Damit meine ich, dass das "+" in 6 + 4 etwas ganz Besonderes ist. Sie können zum Beispiel keinen Zeiger auf diese + Funktion bekommen.
Scala hingegen hat auf diese Weise keine Operatoren. Es hat nur eine große Flexibilität bei der Definition von Methodennamen und ein wenig Vorrang für Nicht-Wortsymbole. Technisch gesehen hat Scala also keine Bedienerüberlastung.
Wie auch immer Sie es nennen möchten, die Überladung von Operatoren ist selbst in C ++ nicht von Natur aus schlecht. Das Problem ist, wenn schlechte Programmierer es missbrauchen. Aber ehrlich gesagt bin ich der Meinung, dass das Wegnehmen der Fähigkeit von Programmierern, die Überlastung von Operatoren zu missbrauchen, nicht dazu führt, dass alle Dinge repariert werden, die Programmierer missbrauchen können. Die eigentliche Antwort ist Mentoring. http://james-iry.blogspot.com/2009/03/operator-overloading-ad-absurdum.html
Trotzdem gibt es Unterschiede zwischen der Überladung von C ++ - Operatoren und der flexiblen Methodenbenennung von Scala, die Scala meiner Meinung nach sowohl weniger missbräuchlich als auch missbräuchlicher machen.
In C ++ besteht die einzige Möglichkeit, eine In-Fix-Notation zu erhalten, in der Verwendung von Operatoren. Andernfalls müssen Sie object.message (Argument) oder pointer-> messsage (Argument) oder function (argument1, argument2) verwenden. Wenn Sie also einen bestimmten DSLish-Stil für Ihren Code wünschen, besteht der Druck, Operatoren zu verwenden.
In Scala können Sie bei jeder gesendeten Nachricht eine Infix-Notation erhalten. "Objektnachrichtenargument" ist vollkommen in Ordnung, was bedeutet, dass Sie keine Nicht-Wortsymbole verwenden müssen, um die Infixnotation zu erhalten.
Das Überladen von C ++ - Operatoren ist im Wesentlichen auf die C-Operatoren beschränkt. In Kombination mit der Einschränkung, dass nur Operatoren verwendet werden dürfen, wird ein Infix verwendet, das Druck auf die Benutzer ausübt, zu versuchen, eine Vielzahl von nicht verwandten Konzepten auf relativ wenige Symbole wie "+" und ">>" abzubilden.
Scala erlaubt eine Vielzahl gültiger Nicht-Wortsymbole als Methodennamen. Zum Beispiel habe ich ein eingebettetes Prolog-DSL, in das Sie schreiben können
Die Symbole: -,!,? Und & werden als normale Methoden definiert. Nur in C ++ & wäre gültig, sodass ein Versuch, dieses DSL in C ++ abzubilden, einige Symbole erfordern würde, die bereits sehr unterschiedliche Konzepte hervorrufen.
Dies öffnet Scala natürlich auch für eine andere Art von Missbrauch. In Scala können Sie eine Methode $! & ^% Nennen, wenn Sie möchten.
Für andere Sprachen, die wie Scala flexibel in der Verwendung von Nicht-Wort-Funktions- und Methodennamen sind, siehe Smalltalk, wo wie Scala jeder "Operator" nur eine andere Methode und Haskell ist, mit der der Programmierer Vorrang und Fixität von flexibel benannten Namen definieren kann Funktionen.
quelle
int main() {return (3).operator+(5);}
Ergebnisse inerror: request for member ‘operator+’ in ‘3’, which is of non-class type ‘int’
Nur von den Unwissenden. In einer Sprache wie C ++ ist dies unbedingt erforderlich, und es fällt auf, dass andere Sprachen, die zunächst eine "puristische" Sichtweise vertraten, diese hinzugefügt haben, sobald ihre Designer herausgefunden haben, wie notwendig dies ist.
quelle
Das Überladen von Operatoren wurde in C ++ nie allgemein als schlechte Idee angesehen - nur der Missbrauch des Überladens von Operatoren wurde als schlechte Idee angesehen. Das Überladen von Operatoren in einer Sprache ist nicht wirklich erforderlich, da sie ohnehin mit ausführlicheren Funktionsaufrufen simuliert werden können. Das Vermeiden einer Überladung von Operatoren in Java vereinfachte die Implementierung und Spezifikation von Java ein wenig und zwang Programmierer, Operatoren nicht zu missbrauchen. In der Java-Community gab es einige Debatten über die Einführung einer Überladung von Operatoren.
Die Vor- und Nachteile der Operatorüberladung in Scala sind dieselben wie in C ++ - Sie können natürlicheren Code schreiben, wenn Sie die Operatorüberladung entsprechend verwenden - und kryptischeren, verschleierten Code, wenn Sie dies nicht tun.
Zu Ihrer Information: Operatoren sind in C ++ nicht als Sonderfunktionen definiert, sie verhalten sich wie jede andere Funktion - obwohl es einige Unterschiede bei der Namenssuche gibt, ob sie Mitgliedsfunktionen sein müssen und die Tatsache, dass sie auf zwei Arten aufgerufen werden können: 1 ) Operatorsyntax und 2) Operatorfunktions-ID-Syntax.
quelle
add(2, multiply(5, 3))
?Dieser Artikel - " Das positive Erbe von C ++ und Java " - beantwortet Ihre Frage direkt.
Java hat fälschlicherweise (laut Autor) das Überladen von Operatoren weggelassen, da es in C ++ kompliziert war, aber vergessen, warum (oder nicht erkannt hat, dass es nicht für Java gilt).
Glücklicherweise bieten höhere Sprachen wie Scala Entwicklern Optionen, während sie immer noch auf derselben JVM ausgeführt werden.
quelle
An der Überlastung des Bedieners ist nichts auszusetzen. Tatsächlich stimmt etwas nicht, wenn der Operator für numerische Typen nicht überladen wird. (Sehen Sie sich Java-Code an, der BigInteger und BigDecimal verwendet.)
C ++ hat jedoch die Tradition, die Funktion zu missbrauchen. Ein häufig genanntes Beispiel ist, dass die Bitshift-Operatoren für E / A überlastet sind.
quelle
=
anstelle von<<
und>>
in den frühen Tagen von C ++ experimentiert hat , aber auf Probleme gestoßen ist, da es nicht die richtige Operator-Priorität hatte (dh es sucht Argumente links oder rechts zuerst). Also waren seine Hände ein bisschen gebunden, was er gebrauchen konnte.Im Allgemeinen ist es keine schlechte Sache.
Neue Sprachen wie C # haben auch eine Überladung des Operators.
Es ist der Missbrauch der Überlastung des Bedieners, der eine schlechte Sache ist.
Es gibt jedoch auch Probleme mit der in C ++ definierten Überladung von Operatoren. Da überladene Operatoren nur syntaktischer Zucker für Methodenaufrufe sind, verhalten sie sich wie Methoden. Andererseits verhalten sich normale integrierte Operatoren nicht wie Methoden. Diese Inkonsistenz kann Probleme verursachen.
Aus dem Kopf Operatoren
||
und&&
.Die eingebauten Versionen davon sind Verknüpfungsoperatoren. Dies gilt nicht für überladene Versionen und hat einige Probleme verursacht.
Die Tatsache, dass + - * / alle denselben Typ zurückgeben, mit dem sie arbeiten (nach der Heraufstufung des Betreibers).
Die überladenen Versionen können alles zurückgeben. (Hier setzt der Missbrauch ein. Wenn Ihre Bediener beginnen, einen vom Benutzer nicht erwarteten Schiedsrichtertyp zurückzugeben Dinge gehen bergab).
quelle
Das Überladen von Operatoren ist nicht etwas, das Sie wirklich sehr oft "brauchen", aber wenn Sie Java verwenden und einen Punkt erreichen, an dem Sie es wirklich brauchen, werden Sie Lust haben, Ihre Fingernägel herauszureißen, nur damit Sie eine Ausrede haben, mit dem Tippen aufzuhören .
Der Code, den Sie gerade gefunden haben, läuft lange über? Ja, Sie müssen das gesamte Los erneut eingeben, damit es mit BigInteger funktioniert. Es gibt nichts Frustrierenderes, als das Rad neu erfinden zu müssen, um den Typ einer Variablen zu ändern.
quelle
Guy Steele argumentierte in seiner Grundsatzrede "Eine Sprache wachsen lassen", dass das Überladen von Operatoren auch in Java erfolgen sollte - es gibt ein Video und eine Transkription davon, und es ist wirklich eine erstaunliche Rede. Sie werden sich fragen, wovon er auf den ersten Seiten spricht, aber wenn Sie weiterlesen, werden Sie den Punkt erkennen und Erleuchtung erreichen. Und die Tatsache, dass er überhaupt eine solche Rede halten konnte, ist auch erstaunlich.
Gleichzeitig inspirierte dieser Vortrag viele Grundlagenforschungen, wahrscheinlich auch Scala - es ist eines dieser Papiere, die jeder lesen sollte, um vor Ort zu arbeiten.
Zurück zum Punkt, in seinen Beispielen geht es hauptsächlich um numerische Klassen (wie BigInteger und einige seltsamere Dinge), aber das ist nicht wesentlich.
Es ist jedoch richtig, dass ein Missbrauch der Überladung von Operatoren zu schrecklichen Ergebnissen führen kann und dass selbst eine ordnungsgemäße Verwendung die Sache komplizieren kann, wenn Sie versuchen, Code zu lesen, ohne die verwendeten Bibliotheken ein wenig zu studieren. Aber ist das eine gute Idee? OTOH, sollten solche Bibliotheken nicht versuchen, ein Operator-Spickzettel für ihre Operatoren aufzunehmen?
quelle
Ich glaube, JEDE Antwort hat dies verpasst. In C ++ können Sie Operatoren überladen, was Sie möchten, aber Sie können die Priorität, mit der sie ausgewertet werden, nicht beeinflussen. Scala hat dieses Problem nicht, IIRC.
Da es sich um eine schlechte Idee handelt, haben die Leute neben Prioritätsproblemen auch wirklich dumme Bedeutungen für die Bediener, und dies hilft selten bei der Lesbarkeit. Scala-Bibliotheken sind besonders schlecht für diese albernen Symbole, die Sie sich jedes Mal merken müssen. Bibliotheksverwalter stecken ihre Köpfe in den Sand und sagen: "Sie müssen es nur einmal lernen." Großartig, jetzt muss ich die kryptische Syntax eines 'cleveren' Autors * lernen, wie viele Bibliotheken ich verwenden möchte. Es wäre nicht so schlimm, wenn es eine Konvention gäbe, die IMMER eine literarische Version der Operatoren liefert.
quelle
Das Überladen von Operatoren war keine C ++ - Erfindung - es stammte von Algol IIRC und selbst Gosling behauptet nicht, dass es im Allgemeinen eine schlechte Idee ist.
quelle
Das einzige, was in C ++ als falsch bekannt ist, ist das Fehlen der Fähigkeit, [] = als separaten Operator zu überladen. Dies könnte schwierig in einem C ++ - Compiler zu implementieren sein, was wahrscheinlich kein offensichtlicher Grund ist, aber es lohnt sich.
quelle
Wie die anderen Antworten gezeigt haben; Die Überlastung des Bedieners selbst ist nicht unbedingt schlecht. Was ist schlecht daran, wenn es so verwendet wird, dass der resultierende Code nicht mehr offensichtlich ist? Wenn Sie sie verwenden, müssen Sie sie im Allgemeinen dazu bringen, die am wenigsten überraschende Sache zu tun (Operator + Do-Division würde Probleme für die Verwendung einer rationalen Klasse verursachen) oder wie Scott Meyers sagt:
Jetzt haben einige Leute die Überlastung des Bedieners mit Dingen wie boost :: spirit auf die Spitze getrieben . Auf dieser Ebene haben Sie keine Ahnung, wie es implementiert ist, aber es macht eine interessante Syntax, um das zu erreichen, was Sie wollen. Ich bin mir nicht sicher, ob das gut oder schlecht ist. Es scheint schön, aber ich habe es nicht benutzt.
quelle
Ich habe noch nie einen Artikel gesehen, in dem behauptet wird, dass die Überladung von C ++ - Operatoren schlecht ist.
Benutzerdefinierte Operatoren ermöglichen Benutzern der Sprache ein einfacheres Maß an Ausdruckskraft und Benutzerfreundlichkeit.
quelle
AFAIK, Bedienerfunktionen haben nichts Besonderes im Vergleich zu "normalen" Elementfunktionen. Natürlich haben Sie nur eine Reihe von Operatoren, die Sie überladen können, aber das macht sie nicht besonders.
quelle