Eine Funktion, die ich in funktionalen Sprachen vermisse, ist die Idee, dass Operatoren nur Funktionen sind. Das Hinzufügen eines benutzerdefinierten Operators ist daher oft so einfach wie das Hinzufügen einer Funktion. Viele prozedurale Sprachen erlauben Überladungen von Operatoren, so dass Operatoren in gewissem Sinne immer noch Funktionen sind (dies gilt sehr für D, wo der Operator als Zeichenfolge in einem Vorlagenparameter übergeben wird).
Wo das Überladen von Operatoren zulässig ist, scheint es oft trivial zu sein, zusätzliche benutzerdefinierte Operatoren hinzuzufügen. Ich habe diesen Blog-Beitrag gefunden , der argumentiert, dass benutzerdefinierte Operatoren aufgrund von Vorrangregeln nicht gut mit der Infix-Notation funktionieren, aber der Autor gibt verschiedene Lösungen für dieses Problem an.
Ich habe mich umgesehen und konnte keine prozeduralen Sprachen finden, die benutzerdefinierte Operatoren in der Sprache unterstützen. Es gibt Hacks (wie Makros in C ++), aber das ist kaum dasselbe wie Sprachunterstützung.
Warum ist diese Funktion nicht häufiger anzutreffen, da sie ziemlich einfach zu implementieren ist?
Ich verstehe, dass dies zu hässlichem Code führen kann, aber das hat Sprachdesigner in der Vergangenheit nicht davon abgehalten, nützliche Funktionen hinzuzufügen, die leicht missbraucht werden können (Makros, ternäre Operatoren, unsichere Zeiger).
Tatsächliche Anwendungsfälle:
- Fehlende Operatoren implementieren (zB Lua hat keine bitweisen Operatoren)
- Mimic D's
~
(Array-Verkettung) - DSLs
- Verwendung
|
als Syntaxzucker im Unix-Pipe-Stil (mit Coroutinen / Generatoren)
Ich bin auch in Sprachen interessiert , die tun benutzerdefinierte Operatoren erlauben, aber ich bin mehr daran interessiert, warum es ausgeschlossen wurde. Ich dachte darüber nach, eine Skriptsprache zu forken, um benutzerdefinierte Operatoren hinzuzufügen, stoppte mich jedoch, als ich merkte, dass ich sie nirgendwo gesehen habe. Es gibt also wahrscheinlich einen guten Grund, warum Sprachdesigner, die schlauer sind als ich, es nicht zugelassen haben.
quelle
Antworten:
Beim Design von Programmiersprachen gibt es zwei diametral entgegengesetzte Denkrichtungen. Zum einen schreiben Programmierer besseren Code mit weniger Einschränkungen, zum anderen schreiben sie besseren Code mit mehr Einschränkungen. Meiner Meinung nach ist die Realität, dass gute erfahrene Programmierer mit weniger Einschränkungen gedeihen, diese Einschränkungen jedoch der Codequalität von Anfängern zugute kommen können.
Benutzerdefinierte Operatoren können für sehr eleganten Code in erfahrenen Händen sorgen und für einen Anfänger einen absolut schrecklichen Code. Ob Ihre Sprache sie enthält oder nicht, hängt also von der Denkweise Ihres Sprachdesigners ab.
quelle
Format
Methode) und wann er ablehnen sollte ( zB Auto-Boxing Argumente zuReferenceEquals
). Je besser Programmierer in der Lage sind, zu sagen, wann bestimmte Schlussfolgerungen unangemessen sind, desto sicherer können geeignete Schlussfolgerungen getroffen werden.Bei der Wahl zwischen der Verkettung von Arrays mit ~ oder mit "myArray.Concat (secondArray)" würde ich wahrscheinlich letzteres vorziehen. Warum? Weil ~ ein völlig bedeutungsloses Zeichen ist, dessen Bedeutung - die der Array-Verkettung - nur in dem spezifischen Projekt angegeben wird, in dem es geschrieben wurde.
Grundsätzlich unterscheiden sich Operatoren, wie Sie sagten, nicht von Methoden. Während Methoden mit lesbaren, verständlichen Namen versehen werden können, die das Verständnis des Codeflusses verbessern, sind Operatoren undurchsichtig und situationsbezogen.
Aus diesem Grund mag ich auch nicht den PHP-
.
Operator (String-Verkettung) oder die meisten Operatoren in Haskell oder OCaml, obwohl in diesem Fall einige allgemein akzeptierte Standards für funktionale Sprachen auftauchen.quelle
+
und mit<<
Sicherheit nicht definiertObject
(wenn ich das in einer nackten Klasse in C ++ mache, bekomme ich "keine Übereinstimmung für Operator + in ...").Ihre Prämisse ist falsch. Es ist nicht "ziemlich trivial zu implementieren". In der Tat bringt es eine Tüte Probleme.
Werfen wir einen Blick auf die vorgeschlagenen "Lösungen" in der Post:
Alles in allem ist dies eine teure Funktion, sowohl in Bezug auf die Komplexität der Parser als auch in Bezug auf die Leistung, und es ist nicht klar, dass dies viele Vorteile mit sich bringen würde. Sicher, die Fähigkeit, neue Operatoren zu definieren , hat einige Vorteile, aber selbst diese sind umstritten (sehen Sie sich einfach die anderen Antworten an, in denen argumentiert wird, dass neue Operatoren keine gute Sache sind).
quelle
Ignorieren wir zunächst das gesamte Argument "Operatoren werden missbraucht, um die Lesbarkeit zu beeinträchtigen" und konzentrieren uns auf die Auswirkungen des Sprachdesigns.
Infix-Operatoren haben mehr Probleme als einfache Prioritätsregeln (obwohl der Link, auf den Sie verweisen, unverblümt ist, wird die Auswirkung dieser Entwurfsentscheidung nicht berücksichtigt). Eines ist Konfliktlösung: Was passiert, wenn Sie definieren
a.operator+(b)
undb.operator+(a)
? Das Vorziehen einer über die andere führt dazu, dass die erwartete kommutative Eigenschaft dieses Operators verletzt wird. Das Auslösen eines Fehlers kann dazu führen, dass Module, die sonst funktionieren würden, einmal zusammengebrochen werden. Was passiert, wenn Sie abgeleitete Typen in den Mix werfen?Tatsache ist, dass Operatoren nicht nur Funktionen sind. Funktionen sind entweder eigenständig oder gehören ihrer Klasse, wodurch eindeutig festgelegt wird, für welchen Parameter (falls vorhanden) die polymorphe Verteilung gilt.
Dabei werden die verschiedenen Verpackungs- und Auflösungsprobleme ignoriert, die von Bedienern verursacht werden. Der Grund, warum Sprachentwickler die Definition von Infix-Operatoren (im Großen und Ganzen) einschränken, liegt darin, dass sie der Sprache eine Menge Probleme bereiten und dabei einen fragwürdigen Nutzen bieten.
Und ehrlich gesagt, weil sie nicht trivial zu implementieren sind.
quelle
+
es böse ist , nicht kommutativ zu sein . Aber ist das wirklich ein Argument gegen benutzerdefinierte Operatoren? Es scheint ein Argument gegen das Überladen von Operatoren im Allgemeinen zu sein.boost::spirit
. Sobald Sie benutzerdefinierte Operatoren zulassen, die sich verschlechtern, gibt es keine gute Möglichkeit, den Vorrang für Mathematik genau zu definieren. Ich habe selbst ein wenig darüber im Kontext einer Sprache geschrieben, die speziell auf Probleme mit willkürlich definierten Operatoren abzielt.Ich glaube , Sie wären überrascht , wie oft Betreiber Überlastungen werden umgesetzt in irgendeiner Form. In vielen Gemeinden werden sie jedoch nicht häufig verwendet.
Warum mit ~ zu einem Array verketten? Warum nicht << wie Ruby verwenden ? Weil die Programmierer, mit denen Sie arbeiten, wahrscheinlich keine Ruby-Programmierer sind. Oder D Programmierer. Was machen sie also, wenn sie auf Ihren Code stoßen? Sie müssen nachsehen, was das Symbol bedeutet.
Ich habe mit einem sehr guten C # -Entwickler zusammengearbeitet, der auch eine Vorliebe für funktionale Sprachen hatte. Aus heiterem Himmel begann er, Monaden über Erweiterungsmethoden und unter Verwendung der Standard-Monadenterminologie in C # einzuführen . Niemand konnte bestreiten, dass ein Teil seines Codes schärfer und noch besser lesbar war, wenn man wusste, was er bedeutete, aber es bedeutete, dass jeder die Monadenterminologie lernen musste, bevor der Code Sinn ergab .
Fair genug, denkst du? Es war nur ein kleines Team. Persönlich stimme ich nicht zu. Jeder neue Entwickler war dazu bestimmt, durch diese Terminologie verwirrt zu werden. Haben wir nicht genug Probleme beim Erlernen einer neuen Domain?
Auf der anderen Seite verwende ich den
??
Operator gerne in C #, da ich erwarte, dass andere C # -Entwickler wissen, was es ist, aber ich würde es nicht in eine Sprache überladen, die es standardmäßig nicht unterstützt.quelle
??
Beispiels.Ich kann mir ein paar Gründe vorstellen:
O(1)
. Bei einer Überladung des Operators kann es sichsomeobject[i]
jedoch leicht um eineO(n)
Operation handeln, die von der Implementierung des Indizierungsoperators abhängt.In der Realität gibt es nur sehr wenige Fälle, in denen das Überladen von Operatoren gerechtfertigt ist, verglichen mit der Verwendung regulärer Funktionen. Ein legitimes Beispiel könnte das Entwerfen einer Klasse für komplexe Zahlen sein, die von Mathematikern verwendet wird, die verstehen, wie mathematische Operatoren für komplexe Zahlen definiert werden. Aber das ist wirklich kein alltäglicher Fall.
Einige interessante Fälle zu berücksichtigen:
+
ist nur eine reguläre Funktion. Sie können Funktionen definieren, wie Sie möchten (normalerweise können Sie sie in separaten Namespaces definieren, um Konflikte mit den eingebauten zu vermeiden+
), einschließlich Operatoren. Aber es gibt eine kulturelle Tendenz, sinnvolle Funktionsnamen zu verwenden, so dass dies nicht viel missbraucht wird. Darüber hinaus wird in der Präfixnotation von Lisp in der Regel ausschließlich verwendet, sodass der "syntaktische Zucker", den Operatorüberladungen bereitstellen, weniger Wert hat.cout << "Hello World!"
irgendjemand?), Aber der Ansatz macht Sinn, wenn man bedenkt, dass C ++ eine komplexe Sprache ist, mit der man auf hohem Niveau programmieren kann, während man sich dennoch der Performance des Metals annähert, um beispielsweise eine komplexe Zahlenklasse zu schreiben, die sich verhält genau so, wie Sie es möchten, ohne die Leistung zu beeinträchtigen. Es liegt in Ihrer eigenen Verantwortung, wenn Sie sich in den Fuß schießen.quelle
Es ist nicht trivial zu implementieren (es sei denn, es ist trivial implementiert). Es bringt Ihnen auch nicht viel, auch wenn es ideal implementiert ist: Die Lesbarkeitsgewinne durch Knappheit werden durch die Lesbarkeitsverluste durch Unvertrautheit und Undurchsichtigkeit ausgeglichen. Kurz gesagt, ist es ungewöhnlich, weil es normalerweise nicht die Zeit der Entwickler oder Benutzer wert ist.
Das heißt, ich kann mir drei Sprachen vorstellen, die das tun, und sie tun es auf unterschiedliche Weise:
quelle
Einer der Hauptgründe, warum benutzerdefinierte Operatoren davon abgehalten werden, ist, dass jeder Operator irgendetwas bedeuten / können kann.
Zum Beispiel wird
cstream
die Überlastung der linken Schicht stark kritisiert.Wenn eine Sprache Bedienerüberladungen zulässt, wird im Allgemeinen empfohlen, das Bedienerverhalten dem Basisverhalten ähnlich zu halten, um Verwirrung zu vermeiden.
Benutzerdefinierte Operatoren erschweren das Parsen erheblich, insbesondere wenn benutzerdefinierte Einstellungsregeln vorhanden sind.
quelle
+
addiere zwei Dinge,-
subtrahiere sie,*
multipliziere sie. Mein Gefühl ist, dass niemand den Programmierer zwingt, Funktionen / Methoden zu erstellen, dieadd
tatsächlich irgendetwas hinzufügen unddoNothing
möglicherweise Atomwaffen starten. Unda.plus(b.minus(c.times(d)).times(e)
ist dann viel weniger lesbara + (b - c * d) * e
(zusätzlicher Bonus - wo im ersten Stich ein Fehler in der Transkription ist). Ich sehe nicht, wie zuerst aussagekräftiger ist ...Wir verwenden keine benutzerdefinierten Operatoren aus dem gleichen Grund, aus dem wir keine benutzerdefinierten Wörter verwenden. Niemand würde ihre Funktion "sworp" nennen. Die einzige Möglichkeit, Ihre Gedanken an eine andere Person weiterzugeben, ist die Verwendung einer gemeinsamen Sprache. Das bedeutet, dass der Gesellschaft, für die Sie Ihren Code schreiben, sowohl Wörter als auch Zeichen (Operatoren) bekannt sein müssen.
Daher sind die Operatoren, die in Programmiersprachen verwendet werden, diejenigen, die uns in der Schule beigebracht wurden (Arithmetik) oder die in der Programmiergemeinschaft etabliert wurden, z. B. Boolesche Operatoren.
quelle
elem
eine großartige Idee ist und sicherlich ein Operator, den jeder verstehen sollte, aber andere scheinen anderer Meinung zu sein.Was Sprachen anbelangt, die eine solche Überladung unterstützen: Scala kann C ++ tatsächlich auf eine viel sauberere und bessere Art und Weise. Die meisten Zeichen können in Funktionsnamen verwendet werden, sodass Sie bei Bedarf Operatoren wie! + * = ++ definieren können. Es gibt eine integrierte Unterstützung für infix (für alle Funktionen, die ein Argument verwenden). Ich denke, Sie können auch die Assoziativität solcher Funktionen definieren. Sie können den Vorrang jedoch nicht definieren (nur mit hässlichen Tricks, siehe hier ).
quelle
Eine Sache, die noch nicht erwähnt wurde, ist der Fall von Smalltalk, bei dem alles (einschließlich Operatoren) eine Nachricht ist, die gesendet wird. „Operatoren“ wie
+
,|
und so weiter sind tatsächlich einstellige Methoden.Alle Methoden können außer Kraft gesetzt werden, so
a + b
bedeutet Integer - Addition , wenna
undb
beide ganze Zahlen sind, und bedeutet Vektoraddition , wenn sie beideOrderedCollection
s.Es gibt keine Vorrangregeln, da dies nur Methodenaufrufe sind. Dies hat eine wichtige Bedeutung für die mathematische Standardnotation:
3 + 4 * 5
bedeutet(3 + 4) * 5
, nicht3 + (4 * 5)
.(Dies ist ein großer Stolperstein für Smalltalk-Neulinge. Durch das Brechen von Mathematikregeln wird ein Sonderfall beseitigt, sodass die gesamte Codebewertung von links nach rechts gleichmäßig verläuft und die Sprache so viel einfacher wird.)
quelle
Sie kämpfen hier gegen zwei Dinge:
In den meisten Sprachen sind Operatoren nicht wirklich als einfache Funktionen implementiert. Möglicherweise verfügen sie über ein Funktionsgerüst, aber der Compiler / die Laufzeit ist sich ausdrücklich ihrer semantischen Bedeutung bewusst und weiß, wie sie effizient in Maschinencode übersetzt werden können. Dies trifft sogar im Vergleich zu integrierten Funktionen zu (weshalb die meisten Implementierungen auch nicht den gesamten Funktionsaufruf-Overhead in ihre Implementierung einbeziehen). Die meisten Operatoren sind Abstraktionen auf höherer Ebene in primitiven Befehlen, die in CPUs zu finden sind (weshalb die meisten Operatoren teilweise arithmetisch, boolesch oder bitweise sind). Sie könnten sie als "spezielle" Funktionen modellieren (nennen Sie sie "primitive" oder "eingebaute" oder "native" oder was auch immer), aber um dies zu tun, ist im Allgemeinen eine sehr robuste Semantik zum Definieren solcher speziellen Funktionen erforderlich. Die Alternative besteht darin, eingebaute Operatoren zu haben, die semantisch wie benutzerdefinierte Operatoren aussehen, aber ansonsten spezielle Pfade im Compiler aufrufen. Das läuft der Antwort auf die zweite Frage zuwider ...
Abgesehen von dem oben erwähnten Problem der maschinellen Übersetzung unterscheiden sich Operatoren syntaktisch nicht wirklich von Funktionen. Sie zeichnen sich in der Regel dadurch aus, dass sie knapp und symbolisch sind, was auf ein signifikantes zusätzliches Merkmal hinweist, das nützlich sein muss: Sie müssen für Entwickler eine allgemein verstandene Bedeutung / Semantik haben. Kurze Symbole vermitteln nicht viel Bedeutung, es sei denn, es handelt sich um eine Kurzform für eine Reihe von Semantiken, die bereits verstanden wurden. Benutzerdefinierte Operatoren sind daher von Natur aus wenig hilfreich, da sie von Natur aus nicht so umfassend verstanden werden. Sie sind genauso sinnvoll wie Funktionsnamen mit einem oder zwei Buchstaben.
Die Überladungen der C ++ - Operatoren bieten einen fruchtbaren Grund, dies zu untersuchen. Die meisten Überladungen von Operatoren "Missbrauch" treten in Form von Überladungen auf, die einen Teil des allgemein verständlichen semantischen Vertrags brechen (ein klassisches Beispiel ist eine Überladung von Operatoren + mit a + b! = B + a oder wobei + eine der beiden Bedingungen ändert) Operanden).
Wenn Sie sich Smalltalk ansehen, das das Überladen von Operatoren und benutzerdefinierte Operatoren ermöglicht, können Sie sehen, wie eine Sprache dies tun könnte und wie nützlich es wäre. In Smalltalk sind Operatoren lediglich Methoden mit unterschiedlichen syntaktischen Eigenschaften (dh sie werden als Infix-Binärcode codiert). Die Sprache verwendet "primitive Methoden" für spezielle beschleunigte Operatoren und Methoden. Sie werden feststellen, dass nur wenige benutzerdefinierte Operatoren erstellt werden und dass sie in der Regel nicht so häufig verwendet werden, wie es der Autor wahrscheinlich beabsichtigt hat. Selbst das Äquivalent einer Operatorüberladung ist selten, da es meist ein Nettoverlust ist, eine neue Funktion als Operator anstelle einer Methode zu definieren, da letztere einen Ausdruck der Semantik der Funktion ermöglicht.
quelle
Ich habe immer festgestellt, dass Operatorüberladungen in C ++ eine bequeme Abkürzung für ein Einzelentwicklerteam sind, die aber auf lange Sicht alle möglichen Verwirrungen hervorruft, einfach weil die Methodenaufrufe auf eine Weise "versteckt" werden, die nicht einfach ist Werkzeuge wie Sauerstoff müssen auseinander genommen werden, und die Leute müssen die Redewendungen verstehen, um sie richtig nutzen zu können.
Manchmal ist es sogar viel schwieriger, einen Sinn zu finden, als man erwarten würde. In einem großen plattformübergreifenden C ++ - Projekt war es einmal eine gute Idee, die Art und Weise zu normalisieren, in der Pfade erstellt wurden, indem ein
FilePath
Objekt (ähnlich dem von JavaFile
) erstellt wurde, mit dem ein anderer Operator / verkettet wurde Pfad-Teil darauf (also könnten Sie so etwas tunFile::getHomeDir()/"foo"/"bar"
und es würde auf allen von uns unterstützten Plattformen das Richtige tun). Jeder, der es sah, sagte im Wesentlichen: "Was zur Hölle? Streicherteilung? ... Oh, das ist süß, aber ich vertraue nicht darauf, dass es das Richtige tut."Ebenso gibt es viele Fälle in der Grafikprogrammierung oder in anderen Bereichen, in denen Vektor- / Matrix-Mathematik häufig in Versuchung gerät, Dinge wie Matrix * Matrix, Vektor * Vektor (Punkt), Vektor% Vektor (Kreuz), Matrix * Vektor ( Matrixtransformation), Matrix ^ Vector (Spezialfall-Matrixtransformation, bei der die homogene Koordinate ignoriert wird - nützlich für Oberflächennormalen) usw. Dies spart zwar ein wenig Analysezeit für die Person, die die Vektor-Mathematik-Bibliothek geschrieben hat, endet jedoch nur up verwirrt das Thema mehr für andere. Das ist es einfach nicht wert.
quelle
Überladungen von Operatoren sind aus dem gleichen Grund eine schlechte Idee wie Überladungen von Methoden: Dasselbe Symbol auf dem Bildschirm hat je nach Umgebung unterschiedliche Bedeutungen. Dies erschwert das gelegentliche Lesen.
Da die Lesbarkeit ein kritischer Aspekt der Wartbarkeit ist, sollten Sie Überladungen immer vermeiden (mit Ausnahme einiger sehr spezieller Fälle). Es ist weitaus besser, wenn jedes Symbol (ob Operator oder alphanumerischer Bezeichner) eine eigene Bedeutung hat.
Zur Veranschaulichung: Wenn Sie beim Lesen von unbekanntem Code auf eine neue alphanum-ID stoßen, die Sie nicht kennen, haben Sie zumindest den Vorteil, dass Sie wissen, dass Sie sie nicht kennen. Sie können es dann nachschlagen. Wenn Sie jedoch einen gemeinsamen Bezeichner oder Operator sehen, dessen Bedeutung Sie kennen, werden Sie mit weitaus geringerer Wahrscheinlichkeit feststellen, dass er tatsächlich überladen wurde, um eine völlig andere Bedeutung zu haben. Um zu wissen, welche Operatoren überladen wurden (in einer Codebasis, die das Überladen in großem Umfang nutzte), müssen Sie den gesamten Code kennen, auch wenn Sie nur einen kleinen Teil davon lesen möchten. Dies würde es schwierig machen, neue Entwickler auf den neuesten Stand zu bringen, und unmöglich machen, Leute für einen kleinen Job zu gewinnen. Dies ist zwar gut für die Arbeitssicherheit von Programmierern, aber wenn Sie für den Erfolg der Codebasis verantwortlich sind, sollten Sie diese Vorgehensweise unbedingt vermeiden.
Da Operatoren von geringer Größe sind, würde das Überladen von Operatoren einen dichteren Code ermöglichen, aber das Festlegen eines dichten Codes ist kein wirklicher Vorteil. Das Lesen einer Zeile mit der doppelten Logik dauert doppelt so lange. Dem Compiler ist das egal. Das einzige Problem ist die Lesbarkeit. Da das Kompaktmachen von Code die Lesbarkeit nicht verbessert, hat die Kompaktheit keinen wirklichen Vorteil. Nehmen Sie Platz und geben Sie eindeutigen Operationen eine eindeutige Kennung, damit Ihr Code auf lange Sicht erfolgreicher ist.
quelle
Ich denke, dass es einige Aspekte einer Programmiersprache gibt, die berücksichtigt werden müssen, wenn es um technische Schwierigkeiten bei der Bearbeitung von Prioritäten und komplexem Parsing geht.
Operatoren sind in der Regel kurze logische Konstrukte, die in der Hauptsprache gut definiert und dokumentiert sind (vergleichen, zuweisen ..). Sie sind auch in der Regel schwer , ohne Dokumentation zu verstehen (vgl
a^b
mitxor(a,b)
zum Beispiel). Es gibt nur eine begrenzte Anzahl von Operatoren, die bei normaler Programmierung sinnvoll sein könnten (>, <, =, + usw.).Meine Idee ist, dass es besser ist, sich an eine Reihe klar definierter Operatoren in einer Sprache zu halten und dann eine Überladung dieser Operatoren durch die Operatoren zuzulassen (mit der sanften Empfehlung, dass die Operatoren dasselbe tun sollten, aber mit einem benutzerdefinierten Datentyp).
Ihre Anwendungsfälle von
~
und|
wären tatsächlich mit einer einfachen Überladung des Operators (C #, C ++ usw.) möglich. DSL ist ein gültiger Nutzungsbereich, aber wahrscheinlich einer der wenigen gültigen Bereiche (aus meiner Sicht). Ich denke jedoch, dass es bessere Werkzeuge gibt, um neue Sprachen zu erstellen. Das Ausführen einer echten DSL-Sprache in einer anderen Sprache ist mit einem dieser Compiler-Compiler-Tools nicht so schwierig. Gleiches gilt für das Argument "LUA erweitern". Eine Sprache wird höchstwahrscheinlich in erster Linie definiert, um Probleme auf eine bestimmte Art und Weise zu lösen, und ist keine Grundlage für Untersprachen (Ausnahmen sind vorhanden).quelle
Ein weiterer Faktor dafür ist, dass es nicht immer einfach ist, eine Operation mit den verfügbaren Operatoren zu definieren. Ich meine, ja, für jede Art von Nummer kann der Operator '*' sinnvoll sein und wird normalerweise in der Sprache oder in vorhandenen Modulen implementiert. Bei den typischen komplexen Klassen, die Sie definieren müssen (z. B. ShipingAddress, WindowManager, ObjectDimensions, PlayerCharacter usw.), ist dieses Verhalten jedoch nicht klar. Was bedeutet das Hinzufügen oder Subtrahieren einer Zahl zu einer Adresse? Zwei Adressen multiplizieren?
Sicher können Sie definieren, dass das Hinzufügen einer Zeichenfolge zu einer ShippingAddress-Klasse einen benutzerdefinierten Vorgang wie "Zeile 1 in Adresse ersetzen" (anstelle der Funktion "setLine1") und das Hinzufügen einer Nummer "Postleitzahl ersetzen" (anstelle von "setZipCode") bedeutet. , aber dann ist der Code nicht sehr lesbar und verwirrend. Wir glauben normalerweise, dass Operatoren in grundlegenden Typen / Klassen verwendet werden, da ihr Verhalten intuitiv, klar und konsistent ist (zumindest, wenn Sie mit der Sprache vertraut sind). Denken Sie an Typen wie Integer, String, ComplexNumbers usw.
Auch wenn das Definieren von Operatoren in bestimmten Fällen sehr nützlich sein kann, ist ihre Implementierung in der Praxis sehr begrenzt, da 99% der Fälle, in denen dies ein klarer Gewinn sein wird, bereits im Basissprachenpaket implementiert sind.
quelle