我问的是关于c#的问题,但我认为它在大多数其他语言中都是一样的。

有人对表达式和语句有很好的定义吗?它们的区别是什么?


当前回答

这些概念的事实基础是:

表达式:一种语法类别,其实例可以求值。

语句:一种语法类别,其实例可能涉及表达式的求值,并且不能保证求值的结果值(如果有的话)可用。

除了最初几十年的FORTRAN上下文之外,公认答案中表达式和语句的定义显然都是错误的:

Expressions can be unvaluated operands. Values are never produced from them. Subexpressions in non-strict evaluations can be definitely unevaluated. Most C-like languages have the so-called short-circuit evaluation rules to conditionally skip some subexpression evaluations not change the final result in spite of the side effects. C and some C-like languages have the notion of unevaluated operand which may be even normatively defined in the language specification. Such constructs are used to avoid the evaluations definitely, so the remained context information (e.g. types or alignment requirements) can be statically distinguished without changing the behavior after the program translation. For example, an expression used as the operand of the sizeof operator is never evaluated. Statements have nothing to do with line constructs. They can do something more than expressions, depending on the language specifications. Modern Fortran, as the direct descendant of the old FORTRAN, has concepts of executable statements and nonexecutable statements. Similarly, C++ defines declarations as the top-level subcategory of a translation unit. A declaration in C++ is a statement. (This is not true in C.) There are also expression-statements like Fortran's executable statements. To the interest of the comparison with expressions, only the "executable" statements matter. But you can't ignore the fact that statements are already generalized to be constructs forming the translation units in such imperative languages. So, as you can see, the definitions of the category vary a lot. The (probably) only remained common property preserved among these languages is that statements are expected to be interpreted in the lexical order (for most users, left-to-right and top-to-bottom).

(BTW,关于C的材料,我想补充一下[引文],因为我不记得DMR是否有这样的意见。似乎不是,否则就没有理由在C语言的设计中保留功能重复:特别是逗号操作符和语句。)

(以下基本原理并不是对最初问题的直接回应,但我觉得有必要澄清这里已经回答过的一些问题。)

然而,在通用编程语言中,我们是否需要特定类别的“语句”是值得怀疑的:

Statements are not guaranteed to have more semantic capabilities over expressions in usual designs. Many languages have already successfully abandon the notion of statements to get clean, neat and consistent overall designs. In such languages, expressions can do everything old-style statements can do: just drop the unused results when the expressions are evaluated, either by leaving the results explicitly unspecified (e.g. in RnRS Scheme), or having a special value (as a value of a unit type) not producible from normal expression evaluations. The lexical order rules of evaluation of expressions can be replaced by explicit sequence control operator (e.g. begin in Scheme) or syntactic sugar of monadic structures. The lexical order rules of other kinds of "statements" can be derived as syntactic extensions (using hygienic macros, for example) to get the similar syntactic functionality. (And it can actually do more.) On the contrary, statements cannot have such conventional rules, because they don't compose on evaluation: there is just no such common notion of "substatement evaluation". (Even if any, I doubt there can be something much more than copy and paste from existed rules of evaluation of expressions.) Typically, languages preserving statements will also have expressions to express computations, and there is a top-level subcategory of the statements preserved to expression evaluations for that subcategory. For example, C++ has the so-called expression-statement as the subcategory, and uses the discarded-value expression evaluation rules to specify the general cases of full-expression evaluations in such context. Some languages like C# chooses to refine the contexts to simplify the use cases, but it bloats the specification more. For users of programming languages, the significance of statements may confuse them further. The separation of rules of expressions and statements in the languages requires more effort to learn a language. The naive lexical order interpretation hides the more important notion: expression evaluation. (This is probably most problematic over all.) Even the evaluations of full expressions in statements are constraint with the lexical order, subexpressions are not (necessarily). Users should ultimately learn this besides any rules coupled to the statements. (Consider how to make a newbie get the point that ++i + ++i is meaningless in C.) Some languages like Java and C# further constraints the order of evaluations of subexpressions to be permissive of ignorance of evaluation rules. It can be even more problematic. This seems overspecified to users who have already learned the idea of expression evaluation. It also encourages the user community to follow the blurred mental model of the language design. It bloats the language specification even more. It is harmful to optimization by missing the expressiveness of nondeterminism on evaluations, before more complicated primitives are introduced. A few languages like C++ (particularly, C++17) specify more subtle contexts of evaluation rules, as a compromise of the problems above. It bloats the language specification a lot. This goes totally against to simplicity to average users...

为什么是语句?不管怎样,历史已经一团糟了。似乎大多数语言设计者都没有仔细选择。

更糟糕的是,它甚至让一些类型系统爱好者(他们对PL历史不够熟悉)产生了一些误解,认为类型系统必须与操作语义上更基本的规则设计有重要关系。

严肃地说,基于类型的推理在许多情况下并不是那么糟糕,但在这个特殊情况下尤其没有建设性。即使是专家也会把事情搞砸。

For example, someone emphasizes the well-typing nature as the central argument against the traditional treatment of undelimited continuations. Although the conclusion is somewhat reasonable and the insights about composed functions are OK (but still far too naive to the essense), this argument is not sound because it totally ignores the "side channel" approach in practice like _Noreturn any_of_returnable_types (in C11) to encode Falsum. And strictly speaking, an abstract machine with unpredictable state is not identical to "a crashed computer".

其他回答

下面是我找到的一个最简单的答案。

原文由Anders Kaseorg回答

语句是执行某些操作的完整代码行,而表达式是代码中求值的任何部分。

可以使用操作符将表达式“水平”组合成更大的表达式,而语句只能通过一个接一个地写入或使用块结构来“垂直”组合。

每个表达式都可以用作语句(其效果是计算表达式并忽略结果值),但大多数语句不能用作表达式。

http://www.quora.com/Python-programming-language-1/Whats-the-difference-between-a-statement-and-an-expression-in-Python

我对这里的答案都不太满意。我查看了c++ (ISO 2008)的语法。然而,出于教学和编程的考虑,答案可能足以区分这两个元素(尽管现实看起来更复杂)。

语句由零个或多个表达式组成,但也可以是其他语言概念。这是语法的扩展巴克斯诺尔形式(语句节选):

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

我们可以看到c++中被认为是语句的其他概念。

表达式-语句是自解释的(一个语句可以由0个或多个表达式组成,仔细阅读语法,这很棘手) 例如,Case是一个带标签的语句 选择语句是if if/else, case 迭代语句是while, do…然而,对于(……) 跳转语句有break, continue, return(可以返回表达式),goto Declaration-statement是声明的集合 try-block是表示try/catch块的语句 在语法中可能还有更多

以下是表达部分的节选:

expression:
        assignment-expression
        expression "," assignment-expression
assignment-expression:
        conditional-expression
        logical-or-expression assignment-operator initializer-clause
        throw-expression

表达式通常是或包含赋值 条件表达式(听起来容易误导人)指的是使用运算符(+,-,*,/,&,|,&&,||,…) 抛出表情——呃?throw子句也是一个表达式

这些概念的事实基础是:

表达式:一种语法类别,其实例可以求值。

语句:一种语法类别,其实例可能涉及表达式的求值,并且不能保证求值的结果值(如果有的话)可用。

除了最初几十年的FORTRAN上下文之外,公认答案中表达式和语句的定义显然都是错误的:

Expressions can be unvaluated operands. Values are never produced from them. Subexpressions in non-strict evaluations can be definitely unevaluated. Most C-like languages have the so-called short-circuit evaluation rules to conditionally skip some subexpression evaluations not change the final result in spite of the side effects. C and some C-like languages have the notion of unevaluated operand which may be even normatively defined in the language specification. Such constructs are used to avoid the evaluations definitely, so the remained context information (e.g. types or alignment requirements) can be statically distinguished without changing the behavior after the program translation. For example, an expression used as the operand of the sizeof operator is never evaluated. Statements have nothing to do with line constructs. They can do something more than expressions, depending on the language specifications. Modern Fortran, as the direct descendant of the old FORTRAN, has concepts of executable statements and nonexecutable statements. Similarly, C++ defines declarations as the top-level subcategory of a translation unit. A declaration in C++ is a statement. (This is not true in C.) There are also expression-statements like Fortran's executable statements. To the interest of the comparison with expressions, only the "executable" statements matter. But you can't ignore the fact that statements are already generalized to be constructs forming the translation units in such imperative languages. So, as you can see, the definitions of the category vary a lot. The (probably) only remained common property preserved among these languages is that statements are expected to be interpreted in the lexical order (for most users, left-to-right and top-to-bottom).

(BTW,关于C的材料,我想补充一下[引文],因为我不记得DMR是否有这样的意见。似乎不是,否则就没有理由在C语言的设计中保留功能重复:特别是逗号操作符和语句。)

(以下基本原理并不是对最初问题的直接回应,但我觉得有必要澄清这里已经回答过的一些问题。)

然而,在通用编程语言中,我们是否需要特定类别的“语句”是值得怀疑的:

Statements are not guaranteed to have more semantic capabilities over expressions in usual designs. Many languages have already successfully abandon the notion of statements to get clean, neat and consistent overall designs. In such languages, expressions can do everything old-style statements can do: just drop the unused results when the expressions are evaluated, either by leaving the results explicitly unspecified (e.g. in RnRS Scheme), or having a special value (as a value of a unit type) not producible from normal expression evaluations. The lexical order rules of evaluation of expressions can be replaced by explicit sequence control operator (e.g. begin in Scheme) or syntactic sugar of monadic structures. The lexical order rules of other kinds of "statements" can be derived as syntactic extensions (using hygienic macros, for example) to get the similar syntactic functionality. (And it can actually do more.) On the contrary, statements cannot have such conventional rules, because they don't compose on evaluation: there is just no such common notion of "substatement evaluation". (Even if any, I doubt there can be something much more than copy and paste from existed rules of evaluation of expressions.) Typically, languages preserving statements will also have expressions to express computations, and there is a top-level subcategory of the statements preserved to expression evaluations for that subcategory. For example, C++ has the so-called expression-statement as the subcategory, and uses the discarded-value expression evaluation rules to specify the general cases of full-expression evaluations in such context. Some languages like C# chooses to refine the contexts to simplify the use cases, but it bloats the specification more. For users of programming languages, the significance of statements may confuse them further. The separation of rules of expressions and statements in the languages requires more effort to learn a language. The naive lexical order interpretation hides the more important notion: expression evaluation. (This is probably most problematic over all.) Even the evaluations of full expressions in statements are constraint with the lexical order, subexpressions are not (necessarily). Users should ultimately learn this besides any rules coupled to the statements. (Consider how to make a newbie get the point that ++i + ++i is meaningless in C.) Some languages like Java and C# further constraints the order of evaluations of subexpressions to be permissive of ignorance of evaluation rules. It can be even more problematic. This seems overspecified to users who have already learned the idea of expression evaluation. It also encourages the user community to follow the blurred mental model of the language design. It bloats the language specification even more. It is harmful to optimization by missing the expressiveness of nondeterminism on evaluations, before more complicated primitives are introduced. A few languages like C++ (particularly, C++17) specify more subtle contexts of evaluation rules, as a compromise of the problems above. It bloats the language specification a lot. This goes totally against to simplicity to average users...

为什么是语句?不管怎样,历史已经一团糟了。似乎大多数语言设计者都没有仔细选择。

更糟糕的是,它甚至让一些类型系统爱好者(他们对PL历史不够熟悉)产生了一些误解,认为类型系统必须与操作语义上更基本的规则设计有重要关系。

严肃地说,基于类型的推理在许多情况下并不是那么糟糕,但在这个特殊情况下尤其没有建设性。即使是专家也会把事情搞砸。

For example, someone emphasizes the well-typing nature as the central argument against the traditional treatment of undelimited continuations. Although the conclusion is somewhat reasonable and the insights about composed functions are OK (but still far too naive to the essense), this argument is not sound because it totally ignores the "side channel" approach in practice like _Noreturn any_of_returnable_types (in C11) to encode Falsum. And strictly speaking, an abstract machine with unpredictable state is not identical to "a crashed computer".

声明中,

语句是构造所有c#程序的过程构建块。语句可以声明局部变量或常量,调用方法,创建对象,或为变量、属性或字段赋值。

由花括号括起来的一系列语句构成了一个代码块。方法体就是代码块的一个例子。

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

c#中的语句通常包含表达式。c#中的表达式是包含文字值、简单名称或操作符及其操作数的代码片段。

表达式,

表达式是可以计算为单个值、对象、方法或名称空间的代码片段。最简单的两种表达式是字面量和简单名称。字面量是一个没有名字的常量值。

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

i和s都是用来标识局部变量的简单名称。当在表达式中使用这些变量时,将检索变量的值并将其用于表达式。

表达式可以求值得到一个值,而语句不返回值(它们是void类型)。

当然,函数调用表达式也可以被视为语句,但除非执行环境有一个特殊的内置变量来保存返回值,否则无法检索它。

面向语句的语言要求所有过程都是语句列表。面向表达式的语言,可能是所有的函数式语言,都是表达式的列表,或者在LISP的情况下,是一个表示表达式列表的长s表达式。

尽管这两种类型都可以组合,但只要类型匹配,大多数表达式都可以任意组合。每种类型的语句都有自己的方式来组合其他语句,如果它们可以做到这一切的话。Foreach和if语句要么要求单个语句,要么要求所有子语句一个接一个地放入语句块中,除非子语句允许它们自己的子语句。

语句还可以包括表达式,而表达式实际上不包括任何语句。不过,lambda表达式是一个例外,它表示一个函数,因此可以包括函数可以包含的任何东西,除非语言只允许有限的lambdas,比如Python的单表达式lambdas。

在基于表达式的语言中,你所需要的只是一个函数的单个表达式,因为所有的控制结构都返回一个值(其中很多返回NIL)。不需要return语句,因为函数中最后求值的表达式就是返回值。