Warum unterstützen die meisten gängigen Sprachen die Syntax „x <y <z“ für boolesche 3-Wege-Vergleiche nicht?

34

Wenn ich zwei Zahlen (oder andere geordnete Entitäten) vergleichen möchte, würde ich dies mit tun x < y. Wenn ich drei davon vergleichen möchte, schlägt der Algebra-Schüler vor, es zu versuchen x < y < z. Der Programmierer in mir antwortet dann mit "nein, das ist nicht gültig, das müssen Sie tun x < y && y < z".

Die meisten Sprachen, auf die ich gestoßen bin, scheinen diese Syntax nicht zu unterstützen, was seltsam ist, da sie in der Mathematik häufig vorkommt. Python ist eine bemerkenswerte Ausnahme. JavaScript scheint eine Ausnahme zu sein, ist jedoch nur ein unglückliches Nebenprodukt der Operatorpräzision und impliziten Konvertierungen. in node.js, 1 < 3 < 2ausgewertet true, weil es wirklich ist (1 < 3) < 2 === true < 2 === 1 < 2.

Meine Frage lautet also: Warum ist x < y < zes in Programmiersprachen nicht allgemein verfügbar, mit der erwarteten Semantik?

JesseTG
quelle
1
Hier ist die Grammatikdatei, die sie handlich direkt in die Python-Dokumentation einfügen
Aaron Hall
Ich kenne andere Sprachen nicht so gut wie Python, aber ich kann mit der Einfachheit von Pythons Interpretation davon sprechen. Vielleicht sollte ich antworten. Aber ich bin nicht einverstanden mit gnasher729s Schlussfolgerung, dass es Schaden anrichtet.
Aaron Hall
@ErikEidt - Die Nachfrage besteht darin, mathematische Ausdrücke so schreiben zu können, wie wir es in der High School (oder früher) gelernt haben. Jeder, der mathematisch geneigt ist, weiß, was $ a <b <c <d $ bedeutet. Nur weil eine Funktion vorhanden ist, müssen Sie sie nicht verwenden. Diejenigen, die es nicht mögen, können jederzeit eine persönliche oder eine Projektregel aufstellen, die dessen Verwendung verbietet.
David Hammen
2
Ich denke, es kommt darauf an, dass es für das C # -Team (als Beispiel) besser ist, LINQ zu erkunden und in Zukunft möglicherweise Typen und Musterabgleiche aufzuzeichnen, als syntaktischen Zucker hinzuzufügen, der Menschen 4 Tastatureingaben erspart und nicht wirklich Fügen Sie jede Ausdruckskraft hinzu (Sie können auch Hilfemethoden schreiben, wie static bool IsInRange<T>(this T candidate, T lower, T upper) where T : IComparable<T>wenn es Sie wirklich stört, &&s zu sehen )
Sara
1
SQL ist ziemlich "Mainstream" und Sie können "x zwischen 1 und 10" schreiben
JoelFan

Antworten:

30

Dies sind binäre Operatoren, die, wenn sie verkettet sind, normalerweise und natürlich einen abstrakten Syntaxbaum erzeugen wie:

normaler abstrakter Syntaxbaum für binäre Operatoren

Wenn ausgewertet (was Sie von Anfang an tun), ergibt dies ein boolesches Ergebnis x < y, woraufhin Sie einen Tippfehler erhalten , der versucht, dies zu tun boolean < z. Damit x < y < zSie wie beschrieben arbeiten können, müssen Sie im Compiler einen speziellen Fall erstellen, um einen Syntaxbaum wie den folgenden zu erstellen:

Spezialfall-Syntaxbaum

Nicht, dass das nicht möglich wäre. Es ist offensichtlich, aber es fügt dem Parser eine gewisse Komplexität hinzu für einen Fall, der nicht wirklich so oft auftritt. Sie erstellen im Grunde genommen ein Symbol, das manchmal wie ein binärer Operator und manchmal wie ein ternärer Operator wirkt, mit allen Auswirkungen der Fehlerbehandlung und den damit verbundenen. Das schafft viel Raum für Fehlentwicklungen, die Sprachdesigner nach Möglichkeit lieber vermeiden würden.

Karl Bielefeldt
quelle
1
msgstr "dann erhalten Sie einen Tippfehler beim Versuch, boolesches <z zu machen" - nicht, wenn der Compiler Verkettung durch Auswertung von y in-place für den z-Vergleich zulässt. "Das schafft viel Raum für Fehlentwicklungen, die Sprachdesigner nach Möglichkeit lieber vermeiden würden." Tatsächlich hat Python kein Problem damit, und die Logik zum Parsen ist auf eine einzige Funktion beschränkt: hg.python.org/cpython/file/tip/Python/ast.c#l1122 - nicht viel Platz für Dinge, die erledigt werden müssen falsch. "Wirkt manchmal wie ein binärer Operator und manchmal wie ein trinärer Operator." In Python ist die gesamte Vergleichskette ternär.
Aaron Hall
2
Ich habe nie gesagt, dass es nicht machbar ist, nur zusätzliche Arbeit mit zusätzlicher Komplexität. Andere Sprachen müssen keinen separaten Code schreiben , nur um ihre Vergleichsoperatoren zu handhaben. Sie erhalten es kostenlos mit anderen Binäroperatoren. Sie müssen nur ihre Priorität angeben.
Karl Bielefeldt
Ja, aber ... gibt es bereits einen ternären Operator in vielen Sprachen?
JensG
1
@JensG Die Bezeichnung ternär bedeutet, dass 3 Argumente verwendet werden. Im Kontext Ihres Links handelt es sich um einen Operator für ternäre Bedingungen. Anscheinend "trinär" in einem Begriff, der für einen Operator geprägt ist, der scheinbar 2, aber tatsächlich 3 benötigt. Mein Hauptproblem bei dieser Antwort ist, dass es sich hauptsächlich um FUD handelt.
Aaron Hall
2
Ich bin einer der Abwähler dieser akzeptierten Antwort. (@JesseTG: Bitte akzeptieren Sie diese Antwort nicht.) Diese Frage verwirrt, was x<y<zbedeutet, oder was noch wichtiger ist x<y<=z. Diese Antwort wird x<y<zals trinärer Operator interpretiert . Genau so sollte dieser gut definierte mathematische Ausdruck nicht interpretiert werden. x<y<zist stattdessen eine Abkürzung für (x<y)&&(y<z). Die einzelnen Vergleiche sind immer noch binär.
David Hammen
37

Warum ist x < y < zes in Programmiersprachen nicht allgemein verfügbar?

Daraus schließe ich

  • Obwohl dieses Konstrukt in der Grammatik einer Sprache trivial zu implementieren ist und Wert für Sprachbenutzer schafft,
  • Der Hauptgrund dafür, dass dies in den meisten Sprachen nicht vorhanden ist, liegt in seiner Bedeutung im Verhältnis zu anderen Merkmalen und in der mangelnden Bereitschaft der Leitungsgremien der Sprachen, dies zu tun
    • ärgern Benutzer mit möglicherweise brechenden Änderungen
    • zu bewegen, um die Funktion zu implementieren (dh: Faulheit).

Einführung

Ich kann aus der Perspektive eines Pythonisten zu dieser Frage sprechen. Ich bin ein Benutzer einer Sprache mit dieser Funktion und möchte die Implementierungsdetails der Sprache studieren. Darüber hinaus bin ich ein wenig mit dem Prozess des Wechsels von Sprachen wie C und C ++ vertraut (der ISO-Standard wird vom Komitee geregelt und nach Jahr versioniert), und ich habe sowohl Ruby als auch Python dabei beobachtet, wie sie wichtige Änderungen umsetzen.

Dokumentation und Implementierung von Python

In der Dokumentation / Grammatik sehen wir, dass wir eine beliebige Anzahl von Ausdrücken mit Vergleichsoperatoren verketten können:

comparison    ::=  or_expr ( comp_operator or_expr )*
comp_operator ::=  "<" | ">" | "==" | ">=" | "<=" | "!="
                   | "is" ["not"] | ["not"] "in"

und in der Dokumentation heißt es weiter:

Vergleiche können beliebig verkettet werden, z. B. x <y <= z ist äquivalent zu x <y und y <= z, außer dass y nur einmal ausgewertet wird (aber in beiden Fällen wird z überhaupt nicht ausgewertet, wenn x <y gefunden wird falsch sein).

Logische Äquivalenz

So

result = (x < y <= z)

ist logisch äquivalent in Bezug auf die Auswertung von x, yund z, mit der Ausnahme, dass yzweimal ausgewertet wird:

x_lessthan_y = (x < y)
if x_lessthan_y:       # z is evaluated contingent on x < y being True
    y_lessthan_z = (y <= z)
    result = y_lessthan_z
else:
    result = x_lessthan_y

Auch hier besteht der Unterschied darin, dass y nur einmal mit ausgewertet wird (x < y <= z).

(Beachten Sie, dass die Klammern völlig unnötig und überflüssig sind, aber ich habe sie zum Nutzen derjenigen verwendet, die aus anderen Sprachen stammen, und der obige Code ist rechtmäßig für Python.)

Untersuchen des analysierten abstrakten Syntaxbaums

Wir können untersuchen, wie Python verkettete Vergleichsoperatoren analysiert:

>>> import ast
>>> node_obj = ast.parse('"foo" < "bar" <= "baz"')
>>> ast.dump(node_obj)
"Module(body=[Expr(value=Compare(left=Str(s='foo'), ops=[Lt(), LtE()],
 comparators=[Str(s='bar'), Str(s='baz')]))])"

Wir können also sehen, dass es für Python oder eine andere Sprache nicht schwierig ist, das zu analysieren.

>>> ast.dump(node_obj, annotate_fields=False)
"Module([Expr(Compare(Str('foo'), [Lt(), LtE()], [Str('bar'), Str('baz')]))])"
>>> ast.dump(ast.parse("'foo' < 'bar' <= 'baz' >= 'quux'"), annotate_fields=False)
"Module([Expr(Compare(Str('foo'), [Lt(), LtE(), GtE()], [Str('bar'), Str('baz'), Str('quux')]))])"

Und im Gegensatz zu der gegenwärtig akzeptierten Antwort ist die ternäre Operation eine generische Vergleichsoperation, die den ersten Ausdruck, eine Iteration spezifischer Vergleiche und eine Iteration von Ausdrucksknoten benötigt, um nach Bedarf ausgewertet zu werden. Einfach.

Fazit zu Python

Ich persönlich finde die Bereichssemantik recht elegant, und die meisten mir bekannten Python-Experten würden die Verwendung der Funktion fördern, anstatt sie als schädlich zu betrachten. Die Semantik wird in der bekannten Dokumentation (wie oben erwähnt) ganz klar angegeben.

Beachten Sie, dass Code viel mehr gelesen als geschrieben wird. Änderungen, die die Lesbarkeit von Code verbessern, sollten aufgegriffen und nicht durch das Hervorrufen von allgemeinen Gespenstern von Angst, Unsicherheit und Zweifel außer Acht gelassen werden .

Warum ist x <y <z in Programmiersprachen nicht allgemein verfügbar?

Ich denke, es gibt eine Zusammenführung von Gründen, die sich um die relative Bedeutung des Merkmals und den relativen Impuls / die Trägheit der Änderung drehen, die die Gouverneure der Sprachen zulassen.

Ähnliche Fragen können zu anderen, wichtigeren Sprachmerkmalen gestellt werden

Warum ist Mehrfachvererbung in Java oder C # nicht verfügbar? Auf beide Fragen gibt es hier keine gute Antwort . Vielleicht waren die Entwickler zu faul, wie Bob Martin behauptet, und die angegebenen Gründe sind lediglich Ausreden. Und Mehrfachvererbung ist ein ziemlich großes Thema in der Informatik. Es ist sicherlich wichtiger als die Verkettung von Operatoren.

Es gibt einfache Problemumgehungen

Die Verkettung von Vergleichsoperatoren ist elegant, aber keineswegs so wichtig wie die Mehrfachvererbung. Und so wie Java und C # Schnittstellen als Workaround haben, so hat auch jede Sprache mehrere Vergleiche - Sie verketten die Vergleiche einfach mit booleschen "und" s, was leicht genug funktioniert.

Die meisten Sprachen werden vom Ausschuss geregelt

Die meisten Sprachen werden vom Komitee entwickelt (anstatt wie Python einen vernünftigen gütigen Diktator für das Leben zu haben). Und ich spekuliere, dass dieses Thema einfach nicht genug Unterstützung fand, um es aus den jeweiligen Ausschüssen herauszuholen.

Können sich die Sprachen ändern, die diese Funktion nicht anbieten?

Wenn eine Sprache x < y < zohne die erwartete mathematische Semantik auskommt, wäre dies eine bahnbrechende Veränderung. Wenn es das überhaupt nicht zulassen würde, wäre es fast trivial hinzuzufügen.

Veränderungen brechen

In Bezug auf die Sprachen mit aktuellen Änderungen: Wir aktualisieren Sprachen mit aktuellen Verhaltensänderungen, aber Benutzer mögen dies in der Regel nicht, insbesondere Benutzer von Funktionen, die möglicherweise fehlerhaft sind. Wenn sich ein Benutzer auf das frühere Verhalten von verlässt x < y < z, würde er wahrscheinlich lautstark protestieren. Und da die meisten Sprachen von Komitees verwaltet werden, bezweifle ich, dass wir viel politischen Willen bekommen würden, eine solche Änderung zu unterstützen.

Aaron Hall
quelle
Ehrlich gesagt, nehme ich kein Problem mit der von Sprachen bereitgestellt Semantik , dass die Kettenvergleichsoperationen wie `x <y <z` aber es ist trivial für einen Entwickler mental map x < y < zzu (x < y) && (y < z). Das mentale Modell für den verketteten Vergleich ist die allgemeine Mathematik. Der klassische Vergleich ist nicht die Mathematik im Allgemeinen, sondern die Boolesche Logik. x < yerzeugt eine binäre Antwort {0}. y < zerzeugt eine binäre Antwort {1}. {0} && {1}erzeugt die beschreibende Antwort. Die Logik ist zusammengesetzt und nicht naiv verkettet.
K. Alan Bates
Um besser zu kommunizieren, habe ich der Antwort einen einzigen Satz vorangestellt, der den gesamten Inhalt direkt zusammenfasst. Es ist ein langer Satz, also habe ich ihn in Kugeln aufgelöst.
Aaron Hall
2
Der Hauptgrund, warum nur wenige Sprachen diese Funktion implementieren, ist, dass vor Guido noch niemand darüber nachgedacht hat. Die Sprachen, die von C erben, können dieses "Richtig" (mathematisch richtig) jetzt nicht bekommen, hauptsächlich, weil die Entwickler von C es vor über 40 Jahren "Falsch" (mathematisch falsch) bekommen haben. Es gibt viele Codes, die davon abhängen, wie diese Sprachen intuitiv interpretiert werden x<y<z. Eine Sprache hat einmal die Chance, so etwas richtig zu machen, und diese eine Chance steht am Anfang der Sprache.
David Hammen
1
@ K.AlanBates Du machst 2 Punkte: 1) Die Operatorverkettung ist schlampig und 2) der syntaktische Zucker hat keinen Wert. Zum ersten: Ich habe gezeigt, dass die Operatorverkettung zu 100% deterministisch ist, nicht wahr? Vielleicht sind einige Programmierer zu faul, um ihre Fähigkeit, das Konstrukt zu verstehen, zu erweitern? Zum zweiten Punkt: Klingt es für mich so, als würden Sie direkt gegen die Lesbarkeit argumentieren? Wird syntaktischer Zucker nicht normalerweise als eine gute Sache angesehen, wenn er die Lesbarkeit verbessert? Wenn es normal ist, so zu denken, warum möchte ein Programmierer dann nicht so kommunizieren? Code sollte geschrieben werden, um gelesen zu werden, nein?
Aaron Hall
2
I have watched both Ruby and Python implement breaking changes.Für diejenigen, die neugierig sind, ist hier eine bahnbrechende Änderung in C # 5.0, die Schleifenvariablen und -schließungen
umfasst
13

Computersprachen versuchen, die kleinstmöglichen Einheiten zu definieren und Sie können sie kombinieren. Die kleinstmögliche Einheit wäre so etwas wie "x <y", was ein boolesches Ergebnis ergibt.

Sie können nach einem ternären Operator fragen. Ein Beispiel wäre x <y <z. Welche Kombinationen von Operatoren erlauben wir nun? Offensichtlich sollte x> y> z oder x> = y> = z oder x> y> = z oder vielleicht x == y == z erlaubt sein. Was ist mit x <y> z? x! = y! = z? Was bedeutet der letzte, x! = Y und y! = Z oder dass alle drei verschieden sind?

Jetzt Argument-Promotions: In C oder C ++ würden Argumente zu einem gemeinsamen Typ heraufgestuft. Also, was bedeutet x <y <z für x ist doppelt, aber y und z sind long long int? Alle drei befördert, um sich zu verdoppeln? Oder wird y einmal und in der anderen Zeit so lange wie doppelt genommen? Was passiert, wenn in C ++ einer oder beide Operatoren überladen sind?

Und erlauben Sie zuletzt eine beliebige Anzahl von Operanden? Wie ein <b> c <d> e <f> g?

Nun, es wird alles sehr kompliziert. Was mir jetzt nichts ausmacht, ist, dass x <y <z einen Syntaxfehler erzeugt. Weil der Nutzen davon im Vergleich zu dem Schaden, der Anfängern zugefügt wird, die nicht herausfinden können, was x <y <z tatsächlich tut, gering ist.

gnasher729
quelle
4
Kurz gesagt, es ist einfach eine schwierige Aufgabe, gut zu gestalten.
Jon Purdy
2
Dies ist nicht wirklich ein Grund zu erklären, warum keine bekannte Sprache diese Funktion enthält. Tatsächlich ist es ziemlich einfach, es in einer gut definierten Weise in eine Sprache aufzunehmen. Es ist nur eine Frage der Anzeige als Liste, die von Operatoren ähnlichen Typs verbunden wird, anstatt dass jeder Operator ein Binäroperator ist. Dasselbe kann für Summen gemacht werden x + y + z, mit dem einzigen Unterschied, dass dies keinen semantischen Unterschied impliziert. Es ist nur so, dass es keiner bekannten Sprache jemals daran gelegen hat.
cmaster
1
Ich denke, dass es in Python eine Art Optimierung ist ( x < y < zdas entspricht, ((x < y) and (y < z))aber ynur einmal ausgewertet wird ), und ich würde mir vorstellen, dass kompilierte Sprachen ihren Weg optimieren. "Weil der Nutzen davon im Vergleich zu dem Schaden, der Anfängern zugefügt wird, die nicht herausfinden können, was x <y <z tatsächlich tut, gering ist." Ich finde es unglaublich nützlich. Wahrscheinlich werde ich dafür -1 ...
Aaron Hall
Wenn es sein Ziel ist, eine Sprache zu entwerfen, die alle Dinge beseitigt, die den dümmsten Programmierer verwirren könnten, gibt es bereits eine solche Sprache: COBOL. Ich würde lieber selbst Python verwenden, wo man tatsächlich schreiben kann a < b > c < d > e < f > g, mit der "offensichtlichen" Bedeutung (a < b) and (b > c) and (c < d) and (d > e) and (e < f) and (f > g). Nur weil Sie schreiben können, heißt das nicht, dass Sie es sollten. Das Eliminieren solcher Monstrositäten ist das Ziel der Codeüberprüfung. Andererseits hat das Schreiben 0 < x < 8in Python die offensichtliche Bedeutung (keine Anführungszeichen), dass x exklusiv zwischen 0 und 8 liegt.
David Hammen
@DavidHammen, ironischerweise erlaubt COBOL in der Tat eine <b <c
JoelFan
10

In vielen Programmiersprachen x < yist ein binärer Ausdruck, der zwei Operanden akzeptiert und zu einem einzigen booleschen Ergebnis ausgewertet wird. Wenn also mehrere Ausdrücke verketten, true < zund false < zwird keinen Sinn machen, und wenn diese Ausdrücke erfolgreich bewerten, sind sie wahrscheinlich das falsche Ergebnis zu produzieren.

Es ist viel einfacher, sich x < yeinen Funktionsaufruf vorzustellen , der zwei Parameter verwendet und ein einziges boolesches Ergebnis erzeugt. Genau so viele Sprachen setzen es unter der Haube um. Es ist kompilierbar, einfach zu kompilieren und funktioniert einfach.

Das x < y < zSzenario ist viel komplizierter. Jetzt ist der Compiler in der Tat hat die Mode drei Funktionen: x < y, y < zund das Ergebnis dieser beiden Werte anded zusammen, die alle im Rahmen einer wohl mehrdeutigen Sprache Grammatik .

Warum haben sie es anders gemacht? Weil es eine eindeutige Grammatik ist, viel einfacher zu implementieren und viel einfacher zu korrigieren ist.

Robert Harvey
quelle
2
Wenn Sie die Sprache entwerfen, haben Sie die Möglichkeit, das richtige Ergebnis zu erzielen.
JesseTG
2
Natürlich beantwortet es die Frage. Wenn die Frage wirklich lautet, warum , lautet die Antwort "weil die Sprachdesigner dies gewählt haben". Wenn Sie eine bessere Antwort finden können, versuchen Sie es. Beachten Sie, dass Gnasher im Wesentlichen genau dasselbe im ersten Absatz seiner Antwort gesagt hat .
Robert Harvey
3
Wieder spaltest du Haare. Programmierer neigen dazu, das zu tun. "Möchtest du den Müll rausbringen?" "Nein." "Wirst du den Müll rausbringen?" "Ja."
Robert Harvey
2
Ich bestreite auch den letzten Absatz. Python unterstützt Kettenvergleiche, und sein Parser ist LL (1). Es ist auch nicht unbedingt schwierig, die Semantik zu definieren und zu implementieren: Python sagt nur, dass dies e1 op1 e2 op2 e3 op3 ...äquivalent ist, mit der e1 op e2 and e2 op2 e3 and ...Ausnahme, dass jeder Ausdruck nur einmal ausgewertet wird. (Übrigens hat diese einfache Regel die verwirrende Nebenwirkung, dass Aussagen wie a == b is Truenicht mehr die beabsichtigte Wirkung haben.)
2
@RobertHarvey re:answerDies war der Punkt, an dem ich mich sofort für meinen Kommentar zur Hauptfrage entschieden habe. Ich halte es nicht für angebracht x < y < z, der Sprachsemantik einen bestimmten Wert beizumessen. (x < y) && (y < z)wird breiter gestützt, ist expliziter, ausdrucksvoller, leichter in seine Bestandteile zu zerlegen, komponierbarer, logischer, leichter umgestaltbar.
K. Alan Bates
6

Die meisten gängigen Sprachen sind (zumindest teilweise) objektorientiert. Grundsätzlich besteht das Grundprinzip von OO darin, dass Objekte Nachrichten an andere Objekte (oder an sich selbst) senden und der Empfänger dieser Nachricht die vollständige Kontrolle darüber hat, wie auf diese Nachricht zu antworten ist.

Nun wollen wir sehen, wie wir so etwas implementieren würden

a < b < c

Wir könnten es streng von links nach rechts auswerten (links-assoziativ):

a.__lt__(b).__lt__(c)

Aber jetzt rufen wir __lt__das Ergebnis von auf a.__lt__(b), das a ist Boolean. Das macht keinen Sinn.

Versuchen wir mal rechtsassoziativ:

a.__lt__(b.__lt__(c))

Nein, das ergibt auch keinen Sinn. Jetzt haben wir a < (something that's a Boolean).

Okay, wie wäre es mit syntaktischem Zucker? Lassen Sie uns eine Kette von n <Vergleichen erstellen, die eine n-1-fache Nachricht senden. Dies könnte bedeuten, wir senden Sie die Nachricht __lt__an a, vorbei bund cals Argument:

a.__lt__(b, c)

Okay, das funktioniert, aber hier gibt es eine merkwürdige Asymmetrie: aMan muss sich entscheiden, ob es weniger ist als b. Aber bich kann mich nicht entscheiden, ob es kleiner ist als c, stattdessen wird diese Entscheidung auch von getroffen a.

Was ist mit der Interpretation als n-fache Nachricht, an die gesendet wird this?

this.__lt__(a, b, c)

Endlich! Das kann funktionieren. Dies bedeutet jedoch, dass die Anordnung von Objekten nicht länger eine Eigenschaft des Objekts ist (z. B. ob akleiner als bweder eine Eigenschaft von anoch von ist b), sondern eine Eigenschaft des Kontexts (dh this).

Aus der Sicht des Mainstreams scheint das komisch. Das ist aber zB in Haskell normal. Beispielsweise kann es mehrere verschiedene Implementierungen der OrdTypenklasse geben, und ob diese akleiner als bist oder nicht , hängt davon ab, welche Typenklasseninstanz sich gerade im Gültigkeitsbereich befindet.

Aber eigentlich ist es gar nicht so komisch! Sowohl Java ( Comparator) als auch .NET ( IComparer) verfügen über Schnittstellen, mit denen Sie Ihre eigene Ordnungsrelation in z. B. Sortieralgorithmen einfügen können. Sie erkennen daher voll und ganz an, dass eine Bestellung nicht an einen Typ gebunden ist, sondern vom Kontext abhängt.

Soweit ich weiß, gibt es derzeit keine Sprachen, die eine solche Übersetzung durchführen. Es gibt jedoch einen Vorrang: Sowohl Ioke als auch Seph haben sogenannte "Trinary Operators" - Operatoren, die syntaktisch binär, aber semantisch ternär sind. Bestimmtes,

a = b

wird nicht so interpretiert, dass die Nachricht als Argument =an die aÜbergabe gesendet wird b, sondern als dass die Nachricht =an die "aktuelle Basis" gesendet wird (ein Konzept, das dem thisÜbergeben ähnlich, aber nicht identisch ist ) aund bals Argumente. So a = bwird interpretiert als

=(a, b)

und nicht

a =(b)

Dies könnte leicht auf n-fache Operatoren verallgemeinert werden.

Beachten Sie, dass dies für OO-Sprachen sehr eigen ist. In OO haben wir immer ein einziges Objekt, das letztendlich für die Interpretation eines Nachrichtensends verantwortlich ist, und wie wir gesehen haben, ist es für so etwas wie a < b < cdas Objekt, das sein sollte, nicht sofort offensichtlich .

Dies gilt jedoch nicht für prozedurale oder funktionale Sprachen. In Scheme , Common Lisp und Clojure ist die <Funktion beispielsweise n-ary und kann mit einer beliebigen Anzahl von Argumenten aufgerufen werden.

Insbesondere <bedeutet nicht "kleiner als", sondern diese Funktionen werden etwas anders interpretiert:

(<  a b c d) ; the sequence a, b, c, d is monotonically increasing
(>  a b c d) ; the sequence a, b, c, d is monotonically decreasing
(<= a b c d) ; the sequence a, b, c, d is monotonically non-decreasing
(>= a b c d) ; the sequence a, b, c, d is monotonically non-increasing
Jörg W. Mittag
quelle
3

Es liegt einfach daran, dass die Sprachdesigner nicht daran gedacht haben oder es nicht für eine gute Idee hielten. Python macht es so, wie Sie es beschrieben haben, mit einer einfachen (fast) LL (1) -Grammatik.

Neil G
quelle
1
Dies wird immer noch mit einer normalen Grammatik in so ziemlich jeder gängigen Sprache analysiert. es wird aus dem Grund, den @RobertHarvey angegeben hat, einfach nicht richtig verstanden.
Mason Wheeler
@MasonWheeler Nein, nicht unbedingt. Wenn die Regeln so geschrieben sind, dass die Vergleiche mit anderen Operatoren austauschbar sind (z. B. weil sie die gleiche Priorität haben), erhalten Sie nicht das richtige Verhalten. Die Tatsache, dass Python alle Vergleiche auf einer Ebene erstellt, ermöglicht es ihm, die Sequenz dann als Konjunktion zu behandeln.
Neil G
1
Nicht wirklich. Wenn Sie 1 < 2 < 3Java oder C # verwenden, haben Sie kein Problem mit der Rangfolge der Operatoren. Sie haben ein Problem mit ungültigen Typen. Das Problem ist, dass dies immer noch genau so analysiert wird, wie Sie es geschrieben haben, aber Sie benötigen eine Spezialfalllogik im Compiler, um es von einer Folge einzelner Vergleiche in einen verketteten Vergleich umzuwandeln.
Mason Wheeler
2
@MasonWheeler Ich sage, dass die Sprache so gestaltet sein muss, dass sie funktioniert. Ein Teil davon ist die richtige Grammatik. (Wenn die Regeln so geschrieben sind, dass die Vergleiche mit anderen Operatoren austauschbar sind, z. B. weil sie die gleiche Priorität haben, erhalten Sie nicht das richtige Verhalten.) Ein weiterer Teil davon ist das Interpretieren des AST als eine Konjunktion, die C ++ geht nicht Der Hauptpunkt meiner Antwort ist, dass es die Entscheidung eines Sprachdesigners ist.
Neil G
@MasonWheeler Ich denke, wir sind uns einig. Ich habe nur hervorgehoben, dass es nicht schwer ist, die richtige Grammatik dafür zu finden. Es ist nur eine Frage des Vorausentscheidens, dass es auf diese Weise funktionieren soll.
Neil G
2

Das folgende C ++ - Programm kompiliert mit nary a peep from clang, auch wenn Warnungen auf die höchstmögliche Stufe gesetzt sind ( -Weverything):

#include <iostream>
int main () { std::cout << (1 < 3 < 2) << '\n'; }

Die Gnu-Compiler-Suite hingegen warnt mich freundlich davor comparisons like 'X<=Y<=Z' do not have their mathematical meaning [-Wparentheses].

Meine Frage lautet also: Warum ist x <y <z in Programmiersprachen mit der erwarteten Semantik nicht allgemein verfügbar?

Die Antwort ist einfach: Abwärtskompatibilität. Es gibt eine Unmenge von Code in freier Wildbahn, der das Äquivalent von verwendet 1<3<2und erwartet, dass das Ergebnis wahr ist.

Ein Sprachdesigner hat nur eine Chance, dies "richtig" zu machen, und das ist der Zeitpunkt, an dem die Sprache zum ersten Mal entworfen wird. Verstehen Sie es "falsch" bedeutet zunächst, dass andere Programmierer dieses "falsche" Verhalten ziemlich schnell ausnutzen. Wenn Sie es beim zweiten Mal "richtig" machen, wird die vorhandene Codebasis zerstört.

David Hammen
quelle
+1, weil dieses Programm '1' als Ergebnis eines Ausdrucks ausgibt, der in der Mathematik offensichtlich falsch ist. Ein reales Beispiel mit unverständlichen Variablennamen würde, obwohl es erfunden wurde, zu einem Debug-Albtraum, wenn diese Sprachfunktion hinzugefügt würde.
Seth Battin
@SethBattin - Dies ist kein Debugging-Albtraum in Python. Das einzige Problem in Python ist if x == y is True : ...: Meiner Meinung nach verdienen Menschen, die solche Codes schreiben, eine ganz besondere, außergewöhnliche Folter, die Torquemada selbst in Ohnmacht fallen lässt (wenn er jetzt lebt).
David Hammen