我问的是关于c#的问题,但我认为它在大多数其他语言中都是一样的。
有人对表达式和语句有很好的定义吗?它们的区别是什么?
我问的是关于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".
其他回答
关于基于表达式的语言的一些事情:
最重要的是:所有内容都返回一个值
用于分隔代码块和表达式的花括号和大括号之间没有区别,因为所有内容都是表达式。不过,这并不会阻止词法作用域:例如,可以为包含其定义的表达式和该表达式中包含的所有语句定义局部变量。
在基于表达式的语言中,所有内容都返回一个值。这一开始可能有点奇怪——(FOR i = 1 TO 10 DO (print i))返回什么?
一些简单的例子:
(1)返回1 (1 + 1)返回2 (1 == 1)返回TRUE (1 == 2)返回FALSE (IF 1 == 1 THEN 10 ELSE 5)返回10 (IF 1 == 2 THEN 10 ELSE 5)返回5
还有一些更复杂的例子:
Some things, such as some function calls, don't really have a meaningful value to return (Things that only produce side effects?). Calling OpenADoor(), FlushTheToilet() or TwiddleYourThumbs() will return some sort of mundane value, such as OK, Done, or Success. When multiple unlinked expressions are evaluated within one larger expression, the value of the last thing evaluated in the large expression becomes the value of the large expression. To take the example of (FOR i = 1 TO 10 DO (print i)), the value of the for loop is "10", it causes the (print i) expression to be evaluated 10 times, each time returning i as a string. The final time through returns 10, our final answer
通常需要稍微改变一下心态,才能最大限度地利用基于表达式的语言,因为所有东西都是表达式,这使得“内联”很多东西成为可能
举个简单的例子:
FOR i = 1 to (IF MyString == "Hello, World!"然后就有10个人这样做了 ( LotsOfCode )
非基于表达式的替换是否完全有效
IF MyString == "Hello, World!"THEN TempVar = 10 ELSE TempVar = 5 FOR i = 1 TO TempVar DO ( LotsOfCode )
在某些情况下,基于表达式的代码所允许的布局对我来说感觉更自然
当然,这可能导致疯狂。作为基于表达式的脚本语言MaxScript的爱好项目的一部分,我设法想出了这个怪物行
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
)
语句->按顺序执行的指令 表达式->返回值的求值
语句基本上就像算法中的步骤或指令,语句执行的结果是指令指针的实现(所谓的汇编程序)。
表达式乍一看并不意味着和执行顺序,它们的目的是求值并返回值。在命令式编程语言中,表达式的求值是有顺序的,但这只是命令式模型的原因,而不是它们的本质。
语句示例:
for
goto
return
if
(所有这些都意味着执行的行(语句)提前到另一行)
表达式示例:
2+2
(这并不是指执行,而是指评估)
语句是一段不返回任何东西的代码,它只是一个独立的执行单元。例如,
if(a>=0)
printf("Hello Humen,I'm a statement");
另一方面,表达式返回或计算一个新值。例如:
if(a>=0)
return a+10;//This is an expression because it evalutes an new value;
or
a=10+y;//This is also an expression because it returns a new value.
你可以在维基百科上找到这个,但是表达式被求值为某个值,而语句没有求值。
因此,表达式可以用在语句中,但不能用在语句中。
请注意,一些语言(如Lisp,我相信Ruby,以及许多其他语言)并不区分语句和表达式……在这样的语言中,所有东西都是一个表达式,并且可以与其他表达式连接。
在面向语句的编程语言中,代码块被定义为语句列表。换句话说,语句是可以放入代码块而不会导致语法错误的一段语法。
维基百科对statement这个词的定义类似
在计算机编程中,语句是命令式编程语言的语法单位,它表示要执行的某些操作。用这种语言编写的程序由一个或多个语句的序列组成
注意后一种说法。(尽管在这种情况下,“一个程序”在技术上是错误的,因为C和Java都拒绝一个不包含任何语句的程序。)
维基百科对表达式的定义是
编程语言中的表达式是一个语法实体,可以对其求值以确定其值
然而,这是错误的,因为在Kotlin中,throw new Exception("")是一个表达式,但当求值时,它只是抛出一个异常,从不返回任何值。
在静态类型编程语言中,每个表达式都有一个类型。然而,这个定义在动态类型编程语言中不起作用。
就我个人而言,我将表达式定义为一段语法,它可以由运算符或函数调用组成,以产生更大的表达式。这其实和维基百科对表达式的解释很相似:
它是一个或多个常量、变量、函数和操作符的组合,编程语言解释(根据其特定的优先级和关联规则)并计算产生(在有状态环境中为“返回”)另一个值
但是,问题是在C编程语言中,给定一个函数执行如下内容:
void executeSomething(void){
return;
}
executessomething()是表达式还是语句?根据我的定义,它是一个语句,因为根据微软C引用语法的定义,
不能以任何方式使用具有void类型的表达式的(不存在的)值,也不能将void表达式(通过隐式或显式转换)转换为除void以外的任何类型
但同一页明确指出,这样的语法是一个表达式。