Ausdruck versus Aussage


431

Ich frage in Bezug auf c #, aber ich gehe davon aus, dass es in den meisten anderen Sprachen dasselbe ist.

Hat jemand eine gute Definition von Ausdrücken und Aussagen und was sind die Unterschiede?


4
Ich finde die Antwort, die Sie gewählt haben, mehrdeutig. Ein Ausdruck macht auch etwas - er ergibt einen Wert. Ich gab eine nicht eindeutige Antwort.
Shelby Moore III

4
@ShelbyMooreIII - Nicht mehrdeutig und auch falsch. Die akzeptierte Antwort ist informell formuliert, aber diese Formulierung macht es leicht zu verstehen - und vor allem ist die Bedeutung, die sie vermittelt, korrekt.
Justin Morgan

@JustinMorgan Leider sind die Definitionen in der akzeptierten Antwort auch offensichtlich falsch ("ergibt einen Wert" / "eine Codezeile") für die meisten zeitgenössischen Sprachen, einschließlich C-ähnlicher: Ausdrücke können in nicht bewerteten Kontexten verwendet werden und Aussagen haben nichts mit Linien zu tun. Obwohl es einige Erklärungen gibt, ist die kurze Antwort verwirrend und irreführend.
FrankHB

Antworten:


520

Ausdruck: Etwas, das einen Wert ergibt. Beispiel: 1 + 2 / x
Anweisung: Eine Codezeile, die etwas bewirkt. Beispiel: GOTO 100

In den frühesten universellen Programmiersprachen wie FORTRAN war die Unterscheidung glasklar. In FORTRAN war eine Anweisung eine Ausführungseinheit, eine Sache, die Sie getan haben. Der einzige Grund, warum es nicht als "Linie" bezeichnet wurde, war, dass es manchmal mehrere Linien umfasste. Ein Ausdruck allein konnte nichts tun ... Sie mussten ihn einer Variablen zuweisen.

1 + 2 / X

ist ein Fehler in FORTRAN, weil es nichts tut. Mit diesem Ausdruck musste man etwas anfangen:

X = 1 + 2 / X

FORTRAN hatte keine Grammatik, wie wir sie heute kennen - diese Idee wurde zusammen mit der Backus-Naur-Form (BNF) als Teil der Definition von Algol-60 erfunden. Zu diesem Zeitpunkt war die semantische Unterscheidung ("einen Wert haben" gegenüber "etwas tun") in der Syntax verankert : Eine Art von Phrase war ein Ausdruck und eine andere eine Aussage, und der Parser konnte sie unterscheiden.

Designer späterer Sprachen verwischten die Unterscheidung: Sie erlaubten syntaktischen Ausdrücken, Dinge zu tun, und sie erlaubten syntaktische Anweisungen, die Werte hatten. Das früheste Beispiel für eine populäre Sprache, das noch erhalten ist, ist C. Die Designer von C haben erkannt, dass kein Schaden angerichtet wurde, wenn Sie einen Ausdruck bewerten und das Ergebnis wegwerfen durften. In C kann jeder syntaktische Ausdruck zu einer Aussage gemacht werden, indem am Ende ein Semikolon angeheftet wird:

1 + 2 / x;

ist eine absolut legitime Aussage, obwohl absolut nichts passieren wird. In ähnlicher Weise kann ein Ausdruck in C Nebenwirkungen haben - er kann etwas ändern.

1 + 2 / callfunc(12);

weil callfuncvielleicht nur etwas Nützliches tun.

Sobald Sie zulassen, dass ein Ausdruck eine Anweisung ist, können Sie auch den Zuweisungsoperator (=) in Ausdrücken zulassen. Deshalb können Sie mit C Dinge wie tun

callfunc(x = 2);

Dies wertet den Ausdruck x = 2 aus (weist x den Wert 2 zu) und übergibt diesen (die 2) dann an die Funktion callfunc.

Diese Unschärfe von Ausdrücken und Anweisungen tritt in allen C-Derivaten (C, C ++, C # und Java) auf, die noch einige Anweisungen (wie while) enthalten, aber die Verwendung fast aller Ausdrücke als Anweisung ermöglichen (nur in C # -Zuweisung). Aufruf-, Inkrement- und Dekrementausdrücke können als Anweisungen verwendet werden (siehe Antwort von Scott Wisniewski ).

Das Vorhandensein von zwei "syntaktischen Kategorien" (der technische Name für die Art von Aussagen und Ausdrücken) kann zu Doppelarbeit führen. Zum Beispiel hat C zwei Formen von Bedingungen, die Anweisungsform

if (E) S1; else S2;

und die Ausdrucksform

E ? E1 : E2

Und manchmal möchten Benutzer eine Duplizierung, die nicht vorhanden ist: In Standard C kann beispielsweise nur eine Anweisung eine neue lokale Variable deklarieren. Diese Funktion ist jedoch so nützlich, dass der GNU C-Compiler eine GNU-Erweiterung bereitstellt, mit der ein Ausdruck a deklarieren kann lokale Variable auch.

Designer anderer Sprachen mochten diese Art der Vervielfältigung nicht und sie sahen früh, dass die syntaktische Unterscheidung zwischen Anweisungen und Ausdrücken nicht allzu nützlich ist , wenn Ausdrücke sowohl Nebenwirkungen als auch Werte haben können - also haben sie sie beseitigt . Haskell, Icon, Lisp und ML sind alle Sprachen, die keine syntaktischen Anweisungen haben - sie haben nur Ausdrücke. Sogar die klassenstrukturierten Schleifen und bedingten Formen werden als Ausdrücke betrachtet und haben Werte - aber keine sehr interessanten.


9
Wenn ich Sie hier nicht falsch interpretiere, scheinen Sie zu behaupten, dass "(setf (drittes foo) 'Gans)" ein Ausdruck ist, keine Aussage, beides, weil es Lisp ist, das "keine Aussagen hat" und weil Lisp mehr als ein Jahrzehnt älter ist als C, was die "früheste populäre Sprache war, um die Grenzen [zwischen Ausdrücken und Aussagen] zu verwischen". Könnten Sie mir die Details erklären?
cjs

2
@Curt Sampson, hast du das als separate Frage gestellt?
Kelly S. French

5
Wenn ich mich nicht irre, callfunc(x = 2);geht xes weiter callfunc, nicht 2. Wenn xes sich um einen Float handelt, callfunc(float)wird nicht aufgerufen callfunc(int). Und wenn Sie in C ++ x=yan übergeben funcund funceine Referenz nehmen und ändern, ändert xsich dies nicht y.
Gabriel

In der obigen Antwort steht geschrieben: "Haskell, ... sind alle Sprachen, die keine syntaktischen Anweisungen haben - sie haben nur Ausdrücke". Ich bin gespannt, warum die whereKlausel in haskell als Ausdruck und nicht als Aussage betrachtet wird. learnyouahaskell.com/syntax-in-functions#where
skgbanga

@skgbanga Ich glaube, es whereist tatsächlich ein Teil der Funktionsdeklaration, nicht Ausdruck oder Anweisung.
Akangka

22
  • Ein Ausdruck ist alles, was einen Wert ergibt: 2 + 2
  • Eine Anweisung ist einer der grundlegenden "Blöcke" der Programmausführung.

Beachten Sie, dass "=" in C tatsächlich ein Operator ist, der zwei Dinge tut:

  • Gibt den Wert des rechten Unterausdrucks zurück.
  • kopiert den Wert des rechten Unterausdrucks in die Variable auf der linken Seite.

Hier ist ein Auszug aus der ANSI C-Grammatik. Sie können sehen, dass C nicht viele verschiedene Arten von Anweisungen hat ... Die meisten Anweisungen in einem Programm sind Ausdrucksanweisungen, dh ein Ausdruck mit einem Semikolon am Ende.

statement
    : labeled_statement
    | compound_statement
    | expression_statement
    | selection_statement
    | iteration_statement
    | jump_statement
    ;

expression_statement
    : ';'
    | expression ';'
    ;

http://www.lysator.liu.se/c/ANSI-C-grammar-y.html


2
Falsche Logik für eine Aussage. Ein deklaratives Programm kann ebenfalls ausgeführt werden, ein deklaratives Programm hat jedoch keine Anweisungen. Eine Aussage ist und tut "Nebenwirkungen" , dh ist zwingend erforderlich. vgl. meine Antwort .
Shelby Moore III

15

Ein Ausdruck gibt einen Wert zurück, eine Anweisung jedoch nicht.

Zum Beispiel:

1 + 2 * 4 * foo.bar()     //Expression
foo.voidFunc(1);          //Statement

Die große Sache zwischen den beiden ist, dass Sie Ausdrücke miteinander verketten können, während Anweisungen nicht verkettet werden können.


6
Sicher Aussagen können verkettet werden. {stmt1; stmt2; stmt3;} ist eine Kette und auch eine (zusammengesetzte) Anweisung.
Hugh Allen

5
foo.voidFunc(1);ist ein Ausdruck mit einem ungültigen Wert. whileund ifsind Aussagen.
tzot

Ich bin neugierig auf die Nichtverkettung von Aussagen. Würde etwas wie "wenn (x> 1) zurückkehren;" als Verkettung zweier Aussagen betrachtet werden?
Simon Tewsi

1
@ SimonTewsi Ich glaube, das returnwird als Untertreibung angesehen.
RastaJedi

@SimonTewsi Die return-Anweisung hier befindet sich implizit im Block der if-Anweisung, ist also Teil der if-Anweisung und nicht verkettet. Der Compiler erlaubt es uns, die geschweiften Klammern hier wegzulassen, da es sich um einen einzelnen Zeilenblock handelt.
user2597608

9

Sie finden dies auf Wikipedia , aber Ausdrücke werden mit einem bestimmten Wert ausgewertet, während Anweisungen keinen ausgewerteten Wert haben.

Ausdrücke können also in Anweisungen verwendet werden, aber nicht umgekehrt.

Beachten Sie, dass einige Sprachen (wie Lisp und ich glaube Ruby und viele andere) nicht zwischen Aussage und Ausdruck unterscheiden ... in solchen Sprachen ist alles ein Ausdruck und kann mit anderen Ausdrücken verkettet werden.


8

Für eine Erklärung wichtiger Unterschiede in der Zusammensetzbarkeit (Verkettbarkeit) von Ausdrücken gegenüber Aussagen ist meine Lieblingsreferenz John Backus 'Turing-Preispapier: Kann Programmierung vom von Neumann-Stil befreit werden? .

Imperative Sprachen (Fortran, C, Java, ...) betonen Aussagen zur Strukturierung von Programmen und haben Ausdrücke als eine Art Nachdenken. Funktionssprachen betonen Ausdrücke. Rein funktionale Sprachen haben so mächtige Ausdrücke, dass Aussagen insgesamt eliminiert werden können.


5

Einfach: Ein Ausdruck ergibt einen Wert, eine Anweisung nicht.


Was macht eine Aussage? Nichts?
Shelby Moore III

1
Es kann etwas tun, aber es bewertet nichts. Das heißt, Sie können das Ergebnis nicht einer Variablen zuweisen, während Sie dies mit einem Ausdruck tun können.
Matthew Schinckel

Und deshalb muss eine Aussage Nebenwirkungen haben, wie meine stark abgelehnte Antwort besagt. Welchen anderen Nutzen könnte eine Aussage möglicherweise haben? Selbst wenn ein NO-OP als Aussage betrachtet würde (es ist nur "Aussage" in der Grammatik, aber nicht auf der Semantik-Ebene, da es nach dem Parsen gelöscht wird und Semantik das ist, was wir hier diskutieren), würde es nicht erklären, was das ist Zum Teufel ist der allgemeine Nutzen einer Aussage.
Shelby Moore III

1
@ShelbyMooreIII Anweisungen müssen nichts tun oder Nebenwirkungen haben. zB {}ist eine Aussage. Das Wort in Angstzitate zu setzen, ändert daran nichts. Anweisungen sind syntaktische Konstrukte mit Semantik. Es gibt keine "Semantik-Ebene" - Sie scheinen sich auf die Ausführung zu beziehen . Sie sagen, Sie versuchen, genau zu sein, aber Sie haben daran versagt. Ihre Beschwerde über "die Unwissenheit der Wähler" ist rein ad hominem; Sie haben keine Informationen über die mentalen Zustände der Downvoter.
Jim Balter

Ja, jeder ist falsch, außer den intellektuell unehrlichen. {}wird als Anweisung in der C # -Sprachenspezifikation definiert.
Jim Balter

5

Ausdrücke können ausgewertet werden, um einen Wert zu erhalten, während Anweisungen keinen Wert zurückgeben (sie sind vom Typ void ).

Funktionsaufrufausdrücke können natürlich auch als Anweisungen betrachtet werden. Wenn die Ausführungsumgebung jedoch nicht über eine spezielle integrierte Variable verfügt, die den zurückgegebenen Wert enthält, kann dieser nicht abgerufen werden.

Anweisungsorientierte Sprachen erfordern, dass alle Prozeduren eine Liste von Anweisungen sind. Ausdrucksorientierte Sprachen, bei denen es sich wahrscheinlich um alle funktionalen Sprachen handelt, sind Listen von Ausdrücken oder im Fall von LISP ein langer S-Ausdruck, der eine Liste von Ausdrücken darstellt.

Obwohl beide Typen zusammengesetzt werden können, können die meisten Ausdrücke beliebig zusammengesetzt werden, solange die Typen übereinstimmen. Jeder Anweisungstyp hat seine eigene Art, andere Anweisungen zu erstellen, wenn sie das alles können. Foreach- und if-Anweisungen erfordern entweder eine einzelne Anweisung oder dass alle untergeordneten Anweisungen nacheinander in einem Anweisungsblock abgelegt werden, es sei denn, die Unteranweisungen lassen ihre eigenen Unteranweisungen zu.

Anweisungen können auch Ausdrücke enthalten, wobei ein Ausdruck keine Anweisungen enthält. Eine Ausnahme wäre jedoch ein Lambda-Ausdruck, der eine Funktion darstellt und daher alles enthalten kann, was eine Funktion enthalten kann, es sei denn, die Sprache erlaubt nur begrenzte Lambdas, wie Pythons Lambdas mit einem Ausdruck.

In einer ausdrucksbasierten Sprache benötigen Sie lediglich einen einzelnen Ausdruck für eine Funktion, da alle Kontrollstrukturen einen Wert zurückgeben (viele von ihnen geben NIL zurück). Eine return-Anweisung ist nicht erforderlich, da der zuletzt ausgewertete Ausdruck in der Funktion der Rückgabewert ist.


Der Typ einer Anweisung ist der unterste Typ. Voidist nicht der unterste Typ. Siehe meine Antwort .
Shelby Moore III

1
Ist der Nulltyp nicht der unterste Typ (Einzelwert von null)? Wäre nicht voidmehr wie der Einheitentyp (aber mit seinem Einzelwert unzugänglich)?
Mark Cidade

Wenn voides sich um den Rückgabetyp einer Funktion handelt, die niemals zurückgegeben wird (z. B. eine throwfehlerhafte Funktion), handelt es sich um den unteren Typ . Ansonsten voidist der Einheitentyp . Sie haben Recht, dass eine Anweisung, die nicht abweichen kann, den Einheitentyp hat. Aber eine Aussage, die abweichen kann, ist der unterste Typ. Aufgrund des Halting-Theorems können wir normalerweise nicht beweisen, dass eine Funktion nicht divergiert, daher denke ich, dass Einheit Fiktion ist. Der untere Typ kann keinen Wert haben, daher kann er keinen einzigen Wert von haben null.
Shelby Moore III

1
In Bezug auf das, was ich vor drei Jahren gesagt habe, weiß ich nicht, ob ich Aussagen immer noch als einen leeren Typ oder irgendeinen Typ wirklich betrachte. In den mir vertrauten anweisungsbasierten Sprachen können nur Werte und alles, was einen Wert speichert oder zurückgibt (z. B. Ausdrücke, Variablen, Elemente und Funktionen), Typen haben. Ich stelle mir den unteren Typ im Allgemeinen als leere Menge vor (keine Werte), und alles, was ontologisch nicht existiert, würde diesen Typ haben. Ein nullWert ist wirklich ein Pseudowert, der angibt, dass sich eine Referenz auf etwas bezieht, das nicht existiert.
Mark Cidade

1
Mark Ich schätze die Rationalität Ihrer Antwort. Sie haben mir im Grunde genommen die Worte aus dem Mund genommen. Und ich hoffe, es war klar, dass ich Ihnen zugegeben habe, dass Sie richtig waren, um den Einheitspunkt zu erhöhen. Ich denke wir sind uns einig. Ich wollte mir nicht die Mühe machen, dies zu erwähnen, aber es scheint, dass einige Leute hier denken, ich sei negativ. Ich versuche nur sachlich zu sein.
Shelby Moore III

4

Einige Dinge über ausdrucksbasierte Sprachen:


Am wichtigsten: Alles gibt einen Wert zurück


Es gibt keinen Unterschied zwischen geschweiften Klammern und geschweiften Klammern zum Abgrenzen von Codeblöcken und Ausdrücken, da alles ein Ausdruck ist. Dies verhindert jedoch nicht das lexikalische Scoping: Eine lokale Variable könnte beispielsweise für den Ausdruck definiert werden, in dem ihre Definition enthalten ist, sowie für alle darin enthaltenen Anweisungen.


In einer ausdrucksbasierten Sprache gibt alles einen Wert zurück. Das kann zunächst etwas seltsam sein - Was kommt (FOR i = 1 TO 10 DO (print i))zurück?

Einige einfache Beispiele:

  • (1) kehrt zurück 1
  • (1 + 1) kehrt zurück 2
  • (1 == 1) kehrt zurück TRUE
  • (1 == 2) kehrt zurück FALSE
  • (IF 1 == 1 THEN 10 ELSE 5) kehrt zurück 10
  • (IF 1 == 2 THEN 10 ELSE 5) kehrt zurück 5

Ein paar komplexere Beispiele:

  • Einige Dinge, wie zum Beispiel einige Funktionsaufrufe, haben keinen wirklich aussagekräftigen Wert (Dinge, die nur Nebenwirkungen hervorrufen?). Wenn Sie aufrufen OpenADoor(), FlushTheToilet()oder TwiddleYourThumbs()einen alltäglichen Wert zurückgeben, z. B. OK, Fertig oder Erfolg.
  • Wenn mehrere nicht verknüpfte Ausdrücke innerhalb eines größeren Ausdrucks ausgewertet werden, wird der Wert des letzten im großen Ausdruck ausgewerteten Elements zum Wert des großen Ausdrucks. Beispiel: (FOR i = 1 TO 10 DO (print i))Der Wert der for-Schleife ist "10". Der (print i)Ausdruck wird zehnmal ausgewertet, wobei jedes Mal i als Zeichenfolge zurückgegeben wird. Das letzte Mal durch Rückkehr 10, unsere endgültige Antwort

Es erfordert oft eine leichte Änderung der Denkweise, um das Beste aus einer ausdrucksbasierten Sprache herauszuholen, da die Tatsache, dass alles ein Ausdruck ist, es ermöglicht, viele Dinge zu „inline“

Als schnelles Beispiel:

 FOR i = 1 to (IF MyString == "Hello, World!" THEN 10 ELSE 5) DO
 (
    LotsOfCode
 )

ist ein vollkommen gültiger Ersatz für das nicht ausdrucksbasierte

IF MyString == "Hello, World!" THEN TempVar = 10 ELSE TempVar = 5 
FOR i = 1 TO TempVar DO
(    
    LotsOfCode  
)

In einigen Fällen fühlt sich das Layout, das ausdrucksbasierter Code zulässt, für mich viel natürlicher an

Dies kann natürlich zum Wahnsinn führen. Im Rahmen eines Hobbyprojekts in einer ausdrucksbasierten Skriptsprache namens MaxScript gelang es mir, diese Monsterlinie zu entwickeln

IF FindSectionStart "rigidifiers" != 0 THEN FOR i = 1 TO (local rigidifier_array = (FOR i = (local NodeStart = FindsectionStart "rigidifiers" + 1) TO (FindSectionEnd(NodeStart) - 1) collect full_array[i])).count DO
(
    LotsOfCode
)

2

Eine Anweisung ist ein Sonderfall eines Ausdrucks mit voidTyp. Die Tendenz der Sprachen, Aussagen anders zu behandeln, verursacht häufig Probleme, und es wäre besser, wenn sie richtig verallgemeinert würden.

Zum Beispiel haben wir in C # die sehr nützliche Func<T1, T2, T3, TResult>überladene Menge generischer Delegaten. Wir müssen aber auch einen entsprechenden Action<T1, T2, T3>Satz haben, und die allgemeine Programmierung höherer Ordnung muss ständig dupliziert werden, um mit dieser unglücklichen Gabelung fertig zu werden.

Triviales Beispiel - Eine Funktion, die prüft, ob eine Referenz null ist, bevor eine andere Funktion aufgerufen wird:

TResult IfNotNull<TValue, TResult>(TValue value, Func<TValue, TResult> func)
                  where TValue : class
{
    return (value == null) ? default(TValue) : func(value);
}

Könnte der Compiler mit der Möglichkeit des TResultSeins umgehen void? Ja. Alles, was es tun muss, ist zu verlangen, dass auf return ein Ausdruck vom Typ folgt void. Das Ergebnis von default(void)wäre vom Typ void, und die übergebene Funktion müsste von der Form sein Func<TValue, void>(die äquivalent wäre Action<TValue>).

Eine Reihe anderer Antworten implizieren, dass Sie Aussagen nicht wie Ausdrücke mit Ausdrücken verketten können, aber ich bin mir nicht sicher, woher diese Idee kommt. Wir können uns das ;, was nach Anweisungen erscheint, als einen binären Infix-Operator vorstellen, der zwei Typausdrücke nimmt voidund sie zu einem einzigen Typausdruck kombiniert void.


Eine Aussage ist kein Sonderfall des Ausdrucks. In einigen Sprachen (dh den meisten C-Nachfolgern) ist es tatsächlich umgekehrt.
Akangka

2

Anweisungen -> Anweisungen, die nacheinander ausgeführt werden sollen
Ausdrücke -> Auswertung, die einen Wert zurückgibt

Anweisungen sind im Grunde genommen wie Schritte oder Anweisungen in einem Algorithmus. Das Ergebnis der Ausführung einer Anweisung ist die Aktualisierung des Anweisungszeigers (im Assembler so genannt).

Ausdrücke implizieren keine Ausführungsreihenfolge auf den ersten Blick, sondern dienen dazu, einen Wert zu bewerten und zurückzugeben. In den imperativen Programmiersprachen hat die Bewertung eines Ausdrucks eine Reihenfolge, aber es liegt nur am imperativen Modell, aber es ist nicht ihre Essenz.

Beispiele für Aussagen:

for
goto
return
if

(Alle implizieren den Fortschritt der Ausführungszeile (Anweisung) zu einer anderen Zeile.)

Beispiel für Ausdrücke:

2+2

(es impliziert nicht die Idee der Ausführung, sondern der Bewertung)


Was ist mit Nebenwirkungen?
Austin Henley

@AustinHenley dafür gibt es keine Anforderung. In der Tat kann ein Ausdruck definitiv eine Nebenwirkung haben.
Akangka vor

1

Aussage ,

Eine Anweisung ist ein prozeduraler Baustein, aus dem alle C # -Programme erstellt werden. Eine Anweisung kann eine lokale Variable oder Konstante deklarieren, eine Methode aufrufen, ein Objekt erstellen oder einer Variablen, Eigenschaft oder einem Feld einen Wert zuweisen.

Eine Reihe von Anweisungen, die von geschweiften Klammern umgeben sind, bilden einen Codeblock. Ein Methodenkörper ist ein Beispiel für einen Codeblock.

bool IsPositive(int number)
{
    if (number > 0)
    {
        return true;
    }
    else
    {
        return false;
    }
}

Anweisungen in C # enthalten häufig Ausdrücke. Ein Ausdruck in C # ist ein Codefragment, das einen Literalwert, einen einfachen Namen oder einen Operator und seine Operanden enthält.

Ausdruck ,

Ein Ausdruck ist ein Codefragment, das zu einem einzelnen Wert, Objekt, einer Methode oder einem Namespace ausgewertet werden kann. Die zwei einfachsten Arten von Ausdrücken sind Literale und einfache Namen. Ein Literal ist ein konstanter Wert ohne Namen.

int i = 5;
string s = "Hello World";

Sowohl i als auch s sind einfache Namen, die lokale Variablen identifizieren. Wenn diese Variablen in einem Ausdruck verwendet werden, wird der Wert der Variablen abgerufen und für den Ausdruck verwendet.


Ich würde lieber schreiben if(number >= 0) return true; else return false;oder noch besser bool? IsPositive(int number) { if(number > 0) return true; else if(number < 0) return false; else return null;}:)
Mahdi Tahsildari

1

Ich bevorzuge die Bedeutung statementim formalen logischen Sinne des Wortes. Es ist eines, das den Status einer oder mehrerer Variablen in der Berechnung ändert und es ermöglicht, eine wahre oder falsche Aussage über deren Wert (e) zu treffen.

Ich denke, es wird immer Verwirrung in der Computerwelt und in der Wissenschaft im Allgemeinen geben, wenn neue Terminologie oder Wörter eingeführt werden, vorhandene Wörter "neu verwendet" werden oder Benutzer die vorhandene, etablierte oder "richtige" Terminologie für das, was sie beschreiben, nicht kennen


1

Ich bin mit keiner der Antworten hier wirklich zufrieden. Ich habe mir die Grammatik für C ++ (ISO 2008) angesehen . Vielleicht reichen die Antworten jedoch aus Gründen der Didaktik und Programmierung aus, um die beiden Elemente zu unterscheiden (die Realität sieht jedoch komplizierter aus).

Eine Anweisung besteht aus null oder mehr Ausdrücken, kann aber auch andere Sprachkonzepte sein. Dies ist das Extended Backus Naur-Formular für die Grammatik (Auszug zur Aussage):

statement:
        labeled-statement
        expression-statement <-- can be zero or more expressions
        compound-statement
        selection-statement
        iteration-statement
        jump-statement
        declaration-statement
        try-block

Wir können die anderen Konzepte sehen, die in C ++ als Anweisungen betrachtet werden.

  • Ausdrucksanweisung s ist selbsterklärend (eine Anweisung kann aus null oder mehr Ausdrücken bestehen, die Grammatik sorgfältig lesen, es ist schwierig)
  • caseZum Beispiel ist eine beschriftete Anweisung
  • Auswahl-Anweisung s sind if if/else,case
  • Iteration-Anweisung s sind while, do...while,for (...)
  • Sprung-Anweisung s sind break, continue, return(kann Ausdruck zurück),goto
  • Deklarationsanweisung ist die Menge der Deklarationen
  • try-block ist eine Anweisung, die try/catchBlöcke darstellt
  • und es könnte noch mehr in der Grammatik geben

Dies ist ein Auszug, der den Ausdrucksteil zeigt:

expression:
        assignment-expression
        expression "," assignment-expression
assignment-expression:
        conditional-expression
        logical-or-expression assignment-operator initializer-clause
        throw-expression
  • Ausdrücke sind oder enthalten häufig Zuordnungen
  • bedingter Ausdruck bezieht sich (Töne irreführend) des Betreibers Verbrauch ( +, -, *, /, &, |, &&, ||, ...)
  • Wurf-Ausdruck - äh? Die throwKlausel ist auch ein Ausdruck

0

Aussagen sind grammatikalisch vollständige Sätze. Ausdrücke sind nicht. Zum Beispiel

x = 5

liest als "x bekommt 5." Dies ist ein vollständiger Satz. Der Code

(x + 5)/9.0

liest, "x plus 5 alle geteilt durch 9.0." Dies ist kein vollständiger Satz. Die Aussage

while k < 10: 
    print k
    k += 1

ist ein vollständiger Satz. Beachten Sie, dass der Loop-Header nicht ist. "while k <10" ist ein Nebensatz.


whileist ein Ausdruck ist einige Sprachen wie Scala. Sie verbinden Grammatik mit Tippen. Siehe meine Antwort .
Shelby Moore III

Hier ist die while-Schleife in scala: tutorialspoint.com/scala/scala_while_loop.htm Die Schleife mit ihrem Prädikat und keinem Körper ist kein grammatikalisch vollständiger Satz. Es ist kein vollständiger Ausdruck. Sie brauchen den Körper, um ihn als Ausdruck zu vervollständigen.
Ncmathsadist

A whilemit einem Körper ist immer noch ein Ausdruck in Scala. Es kann auch eine Aussage sein, wenn es Nebenwirkungen hervorruft, was meine stark herabgestimmte Antwort erlaubt (ein Ausdruck kann auch eine Aussage sein). Meine Antwort ist die einzig richtige. Entschuldigung an alle Leser, die nicht verstehen können.
Shelby Moore III

Was meinst du mit grammatikalisch vollständig? In C (x + 5)/9.0kann definitiv allein als Aussage stehen. Wenn Sie mit grammatikalisch vollständig ein gültiges Programm meinen, erlaubt C nicht, dass Anweisungen als einzelnes Programm allein stehen.
Akangka vor

0

Hier ist der Sommer einer der einfachsten Antworten, die ich gefunden habe.

ursprünglich beantwortet von Anders Kaseorg

Eine Anweisung ist eine vollständige Codezeile, die eine Aktion ausführt, während ein Ausdruck ein beliebiger Abschnitt des Codes ist, der einen Wert ergibt.

Ausdrücke können mithilfe von Operatoren „horizontal“ zu größeren Ausdrücken kombiniert werden, während Anweisungen nur „vertikal“ durch Schreiben nacheinander oder mit Blockkonstrukten kombiniert werden können.

Jeder Ausdruck kann als Anweisung verwendet werden (deren Wirkung darin besteht, den Ausdruck auszuwerten und den resultierenden Wert zu ignorieren), aber die meisten Anweisungen können nicht als Ausdrücke verwendet werden.

http://www.quora.com/Python-programming-language-1/Was-der-Unterschied-zwischen-einer-Aussage-und-einem-Ausdruck-in-Python


0

Die De-facto-Basis dieser Konzepte ist:

Ausdrücke : Eine syntaktische Kategorie, deren Instanz zu einem Wert ausgewertet werden kann.

Anweisung : Eine syntaktische Kategorie, deren Instanz an der Auswertung eines Ausdrucks beteiligt sein kann, und der resultierende Wert der Auswertung (falls vorhanden) sind nicht garantiert verfügbar.

Abgesehen von dem allerersten Kontext für FORTRAN in den frühen Jahrzehnten sind sowohl Definitionen von Ausdrücken als auch Aussagen in der akzeptierten Antwort offensichtlich falsch:

  • Ausdrücke können nicht bewertete Operanden sein. Aus ihnen werden niemals Werte erzeugt.
    • Unterausdrücke in nicht strengen Bewertungen können definitiv nicht bewertet werden.
      • Die meisten C-ähnlichen Sprachen haben die sogenannten Kurzschlussbewertungsregeln , um einige Unterausdrucksbewertungen bedingt zu überspringen und das Endergebnis trotz der Nebenwirkungen nicht zu ändern.
    • C und einige C-ähnliche Sprachen haben den Begriff eines nicht bewerteten Operanden, der sogar normativ in der Sprachspezifikation definiert werden kann. Solche Konstrukte werden verwendet, um die Auswertungen definitiv zu vermeiden, sodass die verbleibenden Kontextinformationen (z. B. Typen oder Ausrichtungsanforderungen) statisch unterschieden werden können, ohne das Verhalten nach der Programmübersetzung zu ändern.
      • Beispielsweise wird ein Ausdruck, der als Operand des sizeofOperators verwendet wird, niemals ausgewertet.
  • Anweisungen haben nichts mit Linienkonstrukten zu tun. Abhängig von den Sprachspezifikationen können sie mehr als nur Ausdrücke.
    • Das moderne Fortran hat als direkter Nachkomme des alten FORTRAN Konzepte für ausführbare Anweisungen und nicht ausführbare Anweisungen .
    • In ähnlicher Weise definiert C ++ Deklarationen als Unterkategorie der obersten Ebene einer Übersetzungseinheit. Eine Deklaration in C ++ ist eine Anweisung. (Dies trifft in C nicht zu.) Es gibt auch Ausdrucksanweisungen wie Fortrans ausführbare Anweisungen.
    • Für den Vergleich mit Ausdrücken sind nur die "ausführbaren" Anweisungen von Bedeutung. Sie können jedoch nicht die Tatsache ignorieren, dass Aussagen bereits als Konstrukte verallgemeinert sind, die die Übersetzungseinheiten in solchen imperativen Sprachen bilden. Wie Sie sehen können, variieren die Definitionen der Kategorie stark. Die (wahrscheinlich) einzige gemeinsame Eigenschaft, die unter diesen Sprachen erhalten bleibt, ist, dass Anweisungen voraussichtlich in der lexikalischen Reihenfolge interpretiert werden (für die meisten Benutzer von links nach rechts und von oben nach unten).

(Übrigens möchte ich dieser Antwort in Bezug auf Materialien zu C [Zitieren erforderlich] hinzufügen, da ich mich nicht erinnern kann, ob DMR solche Meinungen hat. Es scheint nicht, sonst sollte es keine Gründe geben, die Funktionsduplizierung im Design von C beizubehalten : insbesondere der Kommaoperator im Vergleich zu den Anweisungen.)

(Die folgende Begründung ist nicht die direkte Antwort auf die ursprüngliche Frage, aber ich halte es für notwendig, etwas zu klären, das hier bereits beantwortet wurde.)

Es ist jedoch zweifelhaft, dass wir eine bestimmte Kategorie von "Anweisungen" in allgemeinen Programmiersprachen benötigen:

  • Es wird nicht garantiert, dass Anweisungen mehr semantische Fähigkeiten als Ausdrücke in üblichen Designs haben.
    • Viele Sprachen haben den Begriff der Aussagen bereits erfolgreich aufgegeben, um ein sauberes, ordentliches und konsistentes Gesamtdesign zu erhalten.
      • In solchen Sprachen können Ausdrücke alles tun, was Anweisungen im alten Stil können: Löschen Sie einfach die nicht verwendeten Ergebnisse, wenn die Ausdrücke ausgewertet werden, indem Sie die Ergebnisse entweder explizit nicht angeben (z. B. im R n RS-Schema) oder einen speziellen Wert haben (als Wert eines Einheitentyps) nicht aus normalen Ausdrucksbewertungen herstellbar.
      • Die lexikalischen Ordnungsregeln für die Auswertung von Ausdrücken können durch einen expliziten Sequenzsteuerungsoperator (z. B. beginim Schema) oder einen syntaktischen Zucker monadischer Strukturen ersetzt werden.
      • Die lexikalischen Ordnungsregeln anderer Arten von "Anweisungen" können als syntaktische Erweiterungen (z. B. unter Verwendung von Hygienemakros) abgeleitet werden, um die ähnliche syntaktische Funktionalität zu erhalten. (Und es kann tatsächlich mehr .)
    • Im Gegenteil, Aussagen können solche konventionellen Regeln nicht haben, weil sie sich bei der Bewertung nicht zusammensetzen: Es gibt einfach keinen solchen gemeinsamen Begriff der "Substatement-Bewertung". (Selbst wenn überhaupt, bezweifle ich, dass es viel mehr als das Kopieren und Einfügen aus bestehenden Regeln zur Bewertung von Ausdrücken geben kann.)
      • In der Regel enthalten Sprachen, die Anweisungen beibehalten, auch Ausdrücke zum Ausdrücken von Berechnungen, und es gibt eine Unterkategorie der Anweisungen der obersten Ebene, die für Ausdrucksbewertungen für diese Unterkategorie beibehalten werden. Beispielsweise hat C ++ die sogenannte Ausdrucksanweisung als Unterkategorie und verwendet die Auswertungsregeln für Ausdrücke mit verworfenem Wert , um die allgemeinen Fälle von Auswertungsauswertungen in einem solchen Kontext anzugeben. Einige Sprachen wie C # verfeinern die Kontexte, um die Anwendungsfälle zu vereinfachen, aber die Spezifikation wird dadurch aufgebläht.
  • Für Benutzer von Programmiersprachen kann die Bedeutung von Anweisungen sie weiter verwirren.
    • Die Trennung von Regeln für Ausdrücke und Aussagen in den Sprachen erfordert mehr Aufwand, um eine Sprache zu lernen.
    • Die naive lexikalische Ordnungsinterpretation verbirgt den wichtigeren Begriff: Ausdrucksbewertung. (Dies ist wahrscheinlich insgesamt am problematischsten.)
      • Selbst die Auswertung vollständiger Ausdrücke in Anweisungen unterliegt der lexikalischen Reihenfolge, Unterausdrücke nicht (unbedingt). Benutzer sollten dies letztendlich neben allen Regeln lernen, die mit den Anweisungen gekoppelt sind. (Überlegen Sie, wie Sie einen Neuling dazu bringen, den ++i + ++iin C bedeutungslosen Punkt zu erreichen .)
      • Einige Sprachen wie Java und C # schränken die Reihenfolge der Auswertungen von Unterausdrücken weiter ein, um die Unkenntnis der Auswertungsregeln zuzulassen. Es kann noch problematischer sein.
        • Dies scheint für Benutzer, die die Idee der Ausdrucksbewertung bereits gelernt haben, überbestimmt zu sein. Es ermutigt auch die Benutzergemeinschaft, dem verschwommenen mentalen Modell des Sprachdesigns zu folgen.
        • Es bläht die Sprachspezifikation noch mehr auf.
        • Es ist schädlich für die Optimierung, wenn die Ausdruckskraft des Nichtdeterminismus bei Bewertungen fehlt, bevor kompliziertere Grundelemente eingeführt werden.
      • Einige Sprachen wie C ++ (insbesondere C ++ 17) spezifizieren subtilere Kontexte von Bewertungsregeln als Kompromiss der oben genannten Probleme.
        • Es bläht die Sprachspezifikation sehr auf.
        • Dies widerspricht völlig der Einfachheit für durchschnittliche Benutzer ...

Warum also Aussagen? Wie auch immer, die Geschichte ist schon ein Chaos. Es scheint, dass die meisten Sprachdesigner ihre Wahl nicht sorgfältig treffen.

Schlimmer noch, es gibt sogar einigen Typsystem-Enthusiasten (die mit der PL-Geschichte nicht genug vertraut sind) einige Missverständnisse, dass Typsysteme wichtige Dinge mit den grundlegenderen Entwürfen von Regeln für die Betriebssemantik zu tun haben müssen.

Im Ernst, das Denken in Abhängigkeit von den Typen ist in vielen Fällen nicht so schlecht, aber in diesem speziellen Fall besonders nicht konstruktiv. Sogar Experten können es vermasseln.

Zum Beispiel betont jemand die gut typisierende Natur als zentrales Argument gegen die traditionelle Behandlung von unbegrenzten Fortsetzungen . Obwohl die Schlussfolgerung einigermaßen vernünftig ist und die Einsichten über zusammengesetzte Funktionen in Ordnung sind ( aber für die Essenz immer noch viel zu naiv ), ist dieses Argument nicht stichhaltig, da es den "Seitenkanal" -Ansatz in der Praxis wie _Noreturn any_of_returnable_types(in C11) zum Codieren völlig ignoriert Falsum. Und genau genommen ist eine abstrakte Maschine mit unvorhersehbarem Zustand nicht identisch mit "einem abgestürzten Computer".


0

In einer anweisungsorientierten Programmiersprache wird ein Codeblock als Liste von Anweisungen definiert. Mit anderen Worten, eine Anweisung ist eine Syntax, die Sie in einen Codeblock einfügen können, ohne einen Syntaxfehler zu verursachen.

Wikipedia definiert das Wort Aussage ähnlich

In der Computerprogrammierung ist eine Anweisung eine syntaktische Einheit einer imperativen Programmiersprache, die eine auszuführende Aktion ausdrückt. Ein in einer solchen Sprache geschriebenes Programm besteht aus einer Folge von einer oder mehreren Anweisungen

Beachten Sie die letztere Aussage. (obwohl "ein Programm" in diesem Fall technisch falsch ist, weil sowohl C als auch Java ein Programm ablehnen, das aus nichts von Anweisungen besteht.)

Wikipedia definiert den Wortausdruck als

Ein Ausdruck in einer Programmiersprache ist eine syntaktische Entität, die ausgewertet werden kann, um ihren Wert zu bestimmen

Dies ist jedoch falsch, da es sich bei Kotlin throw new Exception("")um einen Ausdruck handelt, der jedoch bei der Auswertung einfach eine Ausnahme auslöst und niemals einen Wert zurückgibt.

In einer statisch typisierten Programmiersprache hat jeder Ausdruck einen Typ. Diese Definition funktioniert jedoch nicht in einer dynamisch typisierten Programmiersprache.

Persönlich definiere ich einen Ausdruck als eine Syntax, die mit einem Operator oder Funktionsaufrufen zusammengesetzt werden kann, um einen größeren Ausdruck zu erhalten. Dies ähnelt tatsächlich der Erklärung des Ausdrucks durch Wikipedia:

Es ist eine Kombination aus einer oder mehreren Konstanten, Variablen, Funktionen und Operatoren, die die Programmiersprache interpretiert (gemäß ihren besonderen Vorrang- und Assoziationsregeln) und berechnet, um in einer zustandsbehafteten Umgebung einen anderen Wert zu erzeugen ("zurückzugeben")

Das Problem liegt jedoch in der Programmiersprache C, wenn eine Funktion ausgeführt wird.

void executeSomething(void){
    return;
}

Ist executeSomething()ein Ausdruck oder eine Aussage? Nach meiner Definition handelt es sich um eine Aussage, da gemäß der Definition in der C-Referenzgrammatik von Microsoft

Sie können weder den (nicht vorhandenen) Wert eines Ausdrucks mit dem Typ void in irgendeiner Weise verwenden, noch können Sie einen void-Ausdruck (durch implizite oder explizite Konvertierung) in einen anderen Typ als void konvertieren

Dieselbe Seite zeigt jedoch deutlich, dass eine solche Syntax ein Ausdruck ist.


-6

Um meine vorherige Antwort zu verbessern und zu validieren, sollten Definitionen von Begriffen der Programmiersprache gegebenenfalls aus der Theorie der Informatik erklärt werden.

Ein Ausdruck hat einen anderen Typ als den unteren Typ, dh er hat einen Wert. Eine Anweisung hat den Typ Unit oder Bottom.

Daraus folgt, dass eine Anweisung in einem Programm nur dann einen Effekt haben kann, wenn sie einen Nebeneffekt erzeugt, da sie entweder keinen Wert zurückgeben kann oder nur den Wert des Unit-Typs zurückgibt, der entweder nicht zuweisbar ist (in einigen Sprachen wie z Ein C void) oder (wie in Scala) kann für eine verzögerte Auswertung der Aussage gespeichert werden.

Offensichtlich haben a @pragmaoder a /*comment*/keinen Typ und unterscheiden sich somit von Aussagen. Somit wäre die einzige Art von Aussage, die keine Nebenwirkungen hätte, eine Nichtoperation. Nicht-Betrieb ist nur als Platzhalter für zukünftige Nebenwirkungen nützlich. Jede andere Handlung aufgrund einer Aussage wäre ein Nebeneffekt. Wiederum ist ein Compiler-Hinweis, z. B. @pragmakeine Anweisung, da er keinen Typ hat.


2
Die Unterscheidung hat nichts mit der Art der Ausdrücke zu tun. Syntaktisch definierte Anweisungen haben in vielen Sprachen überhaupt keine Typen. Obwohl ich theoretisch nicht dagegen bin, einen Typ für solche Begriffe zuzuweisen, sind verschiedene Behandlungen auf @pragmaoder /*comment*/logisch inkonsistent.
FrankHB

-11

Die meisten genau muss eine Aussage eine „Nebenwirkung“ (dh seinen Imperativ ) und ein Ausdruck muss hat einen Wert - Typen (dh nicht der Boden - Typen).

Der Typ einer Anweisung ist der Einheitentyp, aber aufgrund des Halting-Theorems ist die Einheit eine Fiktion, also sagen wir den unteren Typ .


Voidist nicht genau der unterste Typ (es ist nicht der Untertyp aller möglichen Typen). Es existiert in Sprachen, die kein vollständig solides System haben . Das mag nach einer snobistischen Aussage klingen, aber Vollständigkeit wie Abweichungsanmerkungen sind für das Schreiben erweiterbarer Software von entscheidender Bedeutung.

Mal sehen, was Wikipedia zu diesem Thema zu sagen hat.

https://en.wikipedia.org/wiki/Statement_(computer_science)

In der Computerprogrammierung ist eine Anweisung das kleinste eigenständige Element einer imperativen Programmiersprache, das eine auszuführende Aktion ausdrückt .

Viele Sprachen (z. B. C) unterscheiden zwischen Anweisungen und Definitionen, wobei eine Anweisung nur ausführbaren Code enthält und eine Definition einen Bezeichner deklariert, während ein Ausdruck nur einen Wert ergibt.


5
Eine Aussage muss keine Nebenwirkung haben. Zum Beispiel ist in Python passeine Anweisung. Es ist ein No-Op, und es bewertet nichts.
Matthew Schinckel

9
-1 Das ist falsch. Eine Aussage nicht haben , um eine Nebenwirkung haben. Siehe Abschnitt 1.5 der C # -Sprachspezifikation . Nicht nur er nicht angeben , dass Aussagen müssen Nebenwirkungen haben, aber es enthält auch einige Aussagen , die haben keine Nebenwirkungen.
NullUserException

2
@NullUserException Ich habe diesen Abschnitt gelesen. Deklarations-, Ausdrucks-, Auswahl-, Iterations- und Sprunganweisungen können Nebenwirkungen hervorrufen. Wenn es jedoch einen RT-Ausdruck gibt, handelt es sich nicht um eine Aussage. Mir ist klar, dass die Spezifikation Ausdrücke mit Aussagen gleichsetzt, aber diese Frage stellte den Unterschied zwischen ihnen. Entweder hat die Frage keine Antwort, oder Sie nehmen die C # -Spezifikation zu wörtlich. Die am besten gewählte Antwort ist zu sagen, was ich getan habe. Aber "macht etwas" ist bedeutungslos. "Nebeneffekt" ist die sinnvolle Art zu sagen "tut etwas". Wir müssen denken, nicht nur erbrechen.
Shelby Moore III

13
@ShelbyMooreIII Du hast recht. Die offizielle Dokumentation ist falsch . Marc Gravell und Jon Skeet, die möglicherweise die angesehensten C # -Plakate sind, die außerhalb von Eric Lippert auf SO aktiv sind, liegen falsch . Ich und alle anderen, die Sie abgelehnt und Kommentare hinterlassen haben, die unsere Position erklären, sind falsch . Du hast recht. Sie sind eindeutig die einzige Person, die weiß, wovon sie sprechen, da Sie so viel schlauer sind als der ganze Rest von SO.
NullUserException

3
Die genaue Definition von Konzepten wie Anweisung, Ausdruck, Besetzung, Konvertierung usw. zu kennen, hat keinen Einfluss auf 99,999% der täglichen Programmieraufgaben. Denken Sie darüber nach, dass . Außerdem: Die meisten Leute interessieren sich nicht für Haskell und Scala.
NullUserException
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.