Ich entwickle eine Sprache, die sowohl Javascript als auch PHP ersetzen soll. (Ich sehe kein Problem damit. Es ist nicht so, dass eine dieser Sprachen eine große Installationsbasis hat.)
Eines der Dinge, die ich ändern wollte, war, den Zuweisungsoperator in einen Zuweisungsbefehl umzuwandeln und die Möglichkeit zu entfernen, den zurückgegebenen Wert zu verwenden.
x=1; /* Assignment. */
if (x==1) {} /* Comparison. */
x==1; /* Error or warning, I've not decided yet. */
if (x=1) {} /* Error. */
Ich weiß, dass dies bedeuten würde, dass diese einzeiligen Funktionen, die C-Leute so sehr lieben, nicht mehr funktionieren würden. Ich nahm an (mit wenigen Beweisen, die über meine persönlichen Erfahrungen hinausgehen), dass dies in den allermeisten Fällen wirklich als Vergleichsoperation gedacht war.
Oder ist es? Gibt es praktische Verwendungen des Rückgabewerts des Zuweisungsoperators, die nicht einfach umgeschrieben werden konnten? (Für jede Sprache, die ein solches Konzept hat.)
quelle
while((x = getValue()) != null) {}
. Ersetzungen sind hässlicher, da Siebreak
diex = getValue
Zuordnung entweder verwenden oder wiederholen müssen .Antworten:
Technisch gesehen kann es sich lohnen, einige syntaktische Zucker beizubehalten, auch wenn sie trivial ersetzt werden können, wenn sie die Lesbarkeit einiger gängiger Operationen verbessern. Zuweisung als Ausdruck fällt jedoch nicht darunter. Die Gefahr, es anstelle eines Vergleichs zu tippen, bedeutet, dass es selten verwendet wird (manchmal sogar von Styleguides verboten) und bei jeder Verwendung eine doppelte Einstellung hervorruft. Mit anderen Worten, die Vorteile der Lesbarkeit sind in Anzahl und Größe gering.
Ein Blick auf bestehende Sprachen, die dies tun, kann sich lohnen.
if (x)
anstelle vonif (x != null)
oderif (x != 0)
abhängig von der Art von nicht zulässtx
.Allerdings ermöglicht Python einen Sonderfall, auf einmal mehrere Namen zuweisen:
a = b = c
. Dies wird als äquivalent zu angesehenb = c; a = b
und wird gelegentlich verwendet. Daher kann es sich lohnen, Ihre Sprache zu erweitern (aber ich würde es nicht schwitzen, da dieser Zusatz abwärtskompatibel sein sollte).quelle
a = b = c
was die anderen Antworten nicht wirklich hervorbringen.:=
für die Zuordnung.=
ist Aufgabe,==
ist Vergleich.if (a = true)
eine C4706- Warnung aus (The test value in a conditional expression was the result of an assignment.
). GCC mit C wirft ebenfalls awarning: suggest parentheses around assignment used as truth value [-Wparentheses]
. Diese Warnungen können mit einem zusätzlichen Satz von Klammern zum Schweigen gebracht werden. Sie sollen jedoch ausdrücklich darauf hinweisen, dass die Zuweisung beabsichtigt war.a = true
wird als Boolescher Wert ausgewertet und ist daher kein Fehler, sondern löst auch eine entsprechende Warnung in C # aus.Generell nein. Die Vorstellung, dass der Wert eines Zuweisungsausdrucks der zugewiesene Wert ist, bedeutet, dass wir einen Ausdruck haben, der sowohl für seine Nebenwirkung als auch für seinen Wert verwendet werden kann und der von vielen als verwirrend angesehen wird.
Übliche Verwendungszwecke sind normalerweise, um Ausdrücke kompakt zu machen:
hat die Semantik in C # von "konvertiere z in den Typ von y, weise den konvertierten Wert y zu, der konvertierte Wert ist der Wert des Ausdrucks, konvertiere den in den Typ von x, weise x zu".
Aber wir befinden uns bereits im Bereich der impertativen Nebenwirkungen in einem aussagekräftigen Kontext, so dass dies wirklich nur einen sehr geringen zwingenden Vorteil hat
Ähnlich ist es mit
eine Abkürzung für
Wiederum verwenden wir im ursprünglichen Code einen Ausdruck sowohl für seine Nebenwirkungen als auch für seinen Wert und geben eine Aussage ab, die zwei Nebenwirkungen anstelle von einer hat. Beide stinken; Versuchen Sie, eine Nebenwirkung pro Anweisung zu erzielen, und verwenden Sie Ausdrücke für ihre Werte und nicht für ihre Nebenwirkungen.
Wenn Sie wirklich mutig sein und betonen möchten, dass Zuweisung eine Aussage und keine Gleichstellung ist, dann lautet mein Rat: Machen Sie es deutlich zu einer Zuweisungserklärung .
Der Rote. Oder
oder noch besser:
Oder noch besser
Es gibt absolut keine Möglichkeit, mit denen jemand verwechselt werden kann
x == 1
.quelle
x[⍋x←6?40]
auswählt : APL benötigte eine eigene Spezialtastatur, aber es war eine ziemlich erfolgreiche Sprache.a+b*c --> x
? Das kommt mir komisch vor.Viele Sprachen wählen die Methode, mit der die Zuweisung zu einer Anweisung und nicht zu einem Ausdruck gemacht wird, einschließlich Python:
und Golang:
Andere Sprachen haben keine Zuordnung, sondern Gültigkeitsbereichsbindungen, z. B. OCaml:
Ist
let
jedoch ein Ausdruck an sich.Das Zulassen der Zuweisung hat den Vorteil, dass wir den Rückgabewert einer Funktion innerhalb der Bedingung direkt überprüfen können, z. B. in diesem Perl-Snippet:
Perl überprüft die Deklaration zusätzlich nur auf diese Bedingung, was sie sehr nützlich macht. Es warnt auch, wenn Sie innerhalb einer Bedingung zuweisen, ohne dort eine neue Variable zu deklarieren -
if ($foo = $bar)
wird warnen,if (my $foo = $bar)
wird nicht.Die Zuordnung in einer anderen Anweisung ist in der Regel ausreichend, kann jedoch zu Problemen beim Scoping führen:
Golang verlässt sich stark auf Rückgabewerte für die Fehlerprüfung. Es erlaubt daher einer Bedingung, eine Initialisierungsanweisung zu treffen:
Andere Sprachen verwenden ein Typsystem, um nicht-boolesche Ausdrücke in einer Bedingung zu verbieten:
Dies schlägt natürlich fehl, wenn eine Funktion verwendet wird, die einen Booleschen Wert zurückgibt.
Wir haben jetzt verschiedene Mechanismen gesehen, um uns gegen unbeabsichtigte Zuweisungen zu verteidigen:
let
BindungenIch habe sie nach aufsteigenden Präferenzen geordnet - Zuweisungen in Ausdrücken können nützlich sein (und es ist einfach, Pythons Probleme zu umgehen, indem Sie eine explizite Deklarationssyntax und eine andere benannte Argument-Syntax verwenden). Aber es ist in Ordnung, sie zu verbieten, da es viele andere Optionen gibt, die den gleichen Effekt haben.
Fehlerfreier Code ist wichtiger als knapper Code.
quelle
Sie sagten: "Ich dachte mir (mit wenigen Beweisen, die über meine persönlichen Erfahrungen hinausgehen), dass dies in den allermeisten Fällen wirklich als Vergleichsoperation gedacht war."
Warum nicht das Problem beheben?
Verwenden Sie anstelle von = für die Zuweisung und == für die Gleichheitsprüfung: = für die Zuweisung und = (oder sogar ==) für die Gleichheit.
Beobachten:
Wenn Sie es dem Programmierer erschweren möchten, Zuweisung mit Gleichheit zu verwechseln, dann erschweren Sie es.
Zur gleichen Zeit, wenn Sie das Problem WIRKLICH beheben wollten, würden Sie den C-Topf entfernen, der behauptete, Boolesche Werte seien nur Ganzzahlen mit vordefinierten symbolischen Zuckernamen. Bilden Sie sie eine andere Art zusammen. Dann, anstatt zu sagen
Sie zwingen den Programmierer zu schreiben:
Tatsache ist, dass die Zuweisung als Operator ein sehr nützliches Konstrukt ist. Wir haben die Rasierklingen nicht eliminiert, weil sich einige Leute selbst schneiden. Stattdessen erfand König Gillette den Sicherheitsrasierer.
quelle
:=
für die Zuweisung und=
für die Gleichheit könnte dieses Problem beheben, aber auf Kosten der Entfremdung jedes Programmierers, der nicht mit einem kleinen Satz von Nicht-Mainstream-Sprachen aufgewachsen ist. (2) Andere Typen als bools, die unter Bedingungen zulässig sind, sind nicht immer auf das Verwechseln von bools und ganzen Zahlen zurückzuführen. Es reicht aus, anderen Typen eine wahre / falsche Interpretation zu geben. Neuere Sprachen, die keine Angst haben, von C abzuweichen, haben dies für viele andere Typen als Ganzzahlen getan (z. B. betrachtet Python leere Sammlungen als falsch).if (a = b)
lvalue a, boolean a, b zu). In einer Sprache ohne statische Eingabe gibt es auch viel bessere Fehlermeldungen (zur Analysezeit vs. Laufzeit). Außerdem ist die Vermeidung von "a = b vs. a == b-Fehlern" möglicherweise nicht das einzige relevante Ziel. Zum Beispiel möchte ich auch zulassen, dass Codeif items:
bedeutetif len(items) != 0
und dass ich aufgeben muss, um Bedingungen auf Boolesche Werte zu beschränken.Um die Frage tatsächlich zu beantworten: Ja, es gibt zahlreiche Verwendungszwecke, auch wenn sie geringfügig in der Nische liegen.
Zum Beispiel in Java:
Die Alternative ohne Verwendung der eingebetteten Zuweisung erfordert die
ob
außerhalb des Gültigkeitsbereichs der Schleife definierte und zwei separate Code-Speicherorte, die x.next () aufrufen.Es wurde bereits erwähnt, dass Sie mehrere Variablen in einem Schritt zuweisen können.
Diese Art von Dingen wird am häufigsten verwendet, aber kreative Programmierer lassen sich immer mehr einfallen.
quelle
ob
bei jeder Schleife die Zuordnung aufheben und ein neues Objekt erstellen ?Da Sie alle Regeln aufstellen müssen, warum sollten Sie jetzt zulassen, dass die Zuweisung einen Wert ändert, und Zuweisungen in bedingten Schritten einfach nicht zulassen? Dies gibt Ihnen den syntaktischen Zucker, um die Initialisierung zu vereinfachen und gleichzeitig einen häufigen Codierungsfehler zu vermeiden.
Mit anderen Worten, machen Sie dies legal:
Aber mach das illegal:
quelle
a = b = c
scheint orthogonaler und auch einfacher zu implementieren zu sein. Diese beiden Herangehensweisen sind sich nicht einig über die Zuweisung in expressions (a + (b = c)
), aber Sie haben keine Partei ergriffen, daher nehme ich an, dass sie keine Rolle spielen.Durch die Klänge davon sind Sie auf dem Weg, eine ziemlich strenge Sprache zu schaffen.
In diesem Sinne zwingen Sie die Leute zum Schreiben:
anstatt:
scheint eine Verbesserung zu sein, die Menschen davon abhält, Folgendes zu tun:
als sie vorhatten zu tun:
Letztendlich lassen sich solche Fehler jedoch leicht erkennen und warnen, ob es sich um rechtliche Vorschriften handelt oder nicht.
Es gibt jedoch Situationen, in denen Folgendes ausgeführt wird:
bedeutet das nicht
wird wahr sein.
Wenn c tatsächlich eine Funktion c () ist, kann sie bei jedem Aufruf unterschiedliche Ergebnisse liefern. (Es könnte auch rechenintensiv sein ...)
Ebenso, wenn c ein Zeiger auf speicherabgebildete Hardware ist, dann
sind beide wahrscheinlich unterschiedlich und können bei jedem Lesevorgang auch elektronische Auswirkungen auf die Hardware haben.
Es gibt viele andere Permutationen mit Hardware, bei denen Sie genau wissen müssen, aus welchen Speicheradressen gelesen, in welche geschrieben und unter bestimmten zeitlichen Einschränkungen mehrere Zuweisungen auf derselben Leitung ausgeführt werden, und dies schnell, einfach und offensichtlich, ohne das damit verbundene Timing-Risiko temporäre Variablen einführen
quelle
a = b = c
nichta = c; b = c
, es istb = c; a = b
. Dies vermeidet die Wiederholung von Nebenwirkungen und behält auch die Modifikation vona
undb
in derselben Reihenfolge bei. Außerdem sind all diese hardwarebezogenen Argumente ziemlich dumm: Die meisten Sprachen sind keine Systemsprachen und wurden weder zur Lösung dieser Probleme entwickelt, noch werden sie in Situationen verwendet, in denen diese Probleme auftreten. Dies gilt in zweifacher Hinsicht für eine Sprache, die versucht, JavaScript und / oder PHP zu verdrängen.a=b=c
häufig / nützlich ist, sondern Beispiele für Orte, an denen Reihenfolge und Anzahl der Nebenwirkungen berücksichtigt werden müssen. Das ist völlig unabhängig. Schreiben Sie die verkettete Zuordnung korrekt um und beide Varianten sind gleichermaßen korrekt.b
in einem Temp konvertiert und dieser wird in den Typ vona
in einem anderen Temp konvertiert . Der relative Zeitpunkt, zu dem diese Werte tatsächlich gespeichert werden, ist nicht angegeben. Aus Sicht des Sprachdesigns halte ich es für sinnvoll, zu verlangen, dass alle l-Werte in einer Mehrfachzuweisungsanweisung den gleichen Typ haben, und möglicherweise auch, dass keiner von ihnen flüchtig ist.Der größte Vorteil für mich, wenn die Zuweisung ein Ausdruck ist, ist, dass Ihre Grammatik einfacher wird, wenn eines Ihrer Ziele darin besteht, dass "alles ein Ausdruck ist" - insbesondere ein Ziel von LISP.
Python hat das nicht; es hat Ausdrücke und Anweisungen, wobei die Zuweisung eine Anweisung ist. Da Python ein
lambda
Formular jedoch als einen einzigen parametrisierten Ausdruck definiert , können Sie innerhalb eines Lambda keine Variablen zuweisen. Dies ist manchmal unpraktisch, aber kein kritisches Problem, und es ist der einzige Nachteil meiner Erfahrung, dass die Zuweisung eine Aussage in Python ist.Eine Möglichkeit, die Zuweisung bzw. die Auswirkung der Zuweisung als Ausdruck zuzulassen, ohne die
if(x=1)
Unfallgefahr von C einzuführen , besteht darin, ein LISP-ähnlicheslet
Konstrukt zu verwenden, wie(let ((x 2) (y 3)) (+ x y))
es in Ihrer Sprache möglicherweise als ausgewertet wird5
. Die Verwendunglet
dieser Methode muss in Ihrer Sprache technisch gesehen überhaupt nicht zugeordnet werden, wenn Sielet
einen lexikalischen Bereich definieren. Auf diese Weise definiert,let
könnte ein Konstrukt auf dieselbe Weise kompiliert werden wie das Konstruieren und Aufrufen einer verschachtelten Abschlussfunktion mit Argumenten.Auf der anderen Seite, wenn Sie sich nur mit dem
if(x=1)
Fall befassen , aber möchten, dass die Zuweisung ein Ausdruck wie in C ist, reicht es vielleicht aus, nur verschiedene Token zu wählen. Zuordnung:x := 1
oderx <- 1
. Vergleich:x == 1
. Syntaxfehler:x = 1
.quelle
let
unterscheidet sich von der Zuweisung in mehr als der technischen Einführung einer neuen Variablen in einem neuen Bereich. Für den Anfang hat es keine Auswirkung auf den Code außerhalb deslet
Körpers des Benutzers und erfordert daher, den gesamten Code (was die Variable verwenden sollte) weiter zu verschachteln, ein wesentlicher Nachteil in zuweisungsintensivem Code. Wenn man diesen Weg beschreitenset!
würde , wäre dies das bessere Lisp-Analogon - ganz anders als im Vergleich, aber ohne Verschachtelung oder ein neues Oszilloskop.Tatsächlich. Dies ist nichts Neues, alle sicheren Teilmengen der C-Sprache haben bereits diese Schlussfolgerung gezogen.
MISRA-C, CERT-C und so weiter verbieten Zuteilung innerhalb von Bedingungen, einfach weil es gefährlich ist.
Es gibt keinen Fall, in dem Code, der sich auf die Zuweisung innerhalb von Bedingungen stützt, nicht umgeschrieben werden kann.
Darüber hinaus warnen solche Standards auch davor, Code zu schreiben, der auf der Reihenfolge der Bewertung beruht. Ein
x=y=z;
solcher Fall ist die Mehrfachzuweisung in einer einzelnen Zeile . Wenn eine Zeile mit mehreren Zuweisungen Nebenwirkungen enthält (Aufrufen von Funktionen, Zugreifen auf flüchtige Variablen usw.), können Sie nicht wissen, welche Nebenwirkungen zuerst auftreten.Zwischen der Auswertung der Operanden liegen keine Sequenzpunkte. Daher können wir nicht wissen, ob der Unterausdruck
y
vorher oder nachher ausgewertet wirdz
: Es handelt sich um ein nicht angegebenes Verhalten in C. Daher ist ein solcher Code möglicherweise unzuverlässig, nicht portierbar und nicht konform mit den genannten sicheren Untermengen von C.Die Lösung wäre gewesen, den Code durch zu ersetzen
y=z; x=y;
. Dies fügt einen Sequenzpunkt hinzu und garantiert die Reihenfolge der Auswertung.Ausgehend von all den Problemen, die dies in C verursachte, würde jede moderne Sprache sowohl die Zuweisung innerhalb von Bedingungen als auch die Mehrfachzuweisung in einer einzelnen Zeile verbessern.
quelle