可选分号


10

通常,在通用命令式语言中,分号作为语句分隔符是必需的,或者是完全不允许使用的(例如C和Python)。

但是,某些语言(例如JavaScript)允许您选择不使用分号来分隔语句,而支持其他分隔符(例如换行符)。

这背后的设计决策是什么?我知道在同一行上编写多个语句时,分号是必不可少的,但是还有其他理由使分号成为强制性的(除了C之后)?


1
您需要考虑语句终止符(perl,c)和语句定界符(javascript,pascal)。

5
在Python中,分号可用于在同一行上分隔多个语句。并且由于允许使用“空”语句,因此可以在大多数语句的末尾使用分号。
2013年

1
I understand that semicolons are essential when writing multiple statements on the same line-取决于语言。我最喜欢的一个根本没有这样的定界符,下一条语句在所有函数参数用完后开始。
2013年

1
@MichaelT:我认为您的分类是不正确的:Perl可能属于这两个类别,而JavaScript实际上位于“语句终止符”阵营中(因为要求实现}在文件末尾推断出分号)。
ruakh

是的,完全取决于语言。我个人的猜测是分号只是大多数语言设计师遵循的一种约定俗成的约定。至少从更自然的语言角度来看,这是有道理的。顺便说一下,与{和}的代码块相同:它们被许多种语言使用,但是并不是所有语言都使用,实际上您不必这样做。这背后没有普遍的原因。
JensG

Answers:


24

使它们成为强制性的(或完全禁止它们)可以减少极端情况的发生,消除潜在的晦涩错误,并简化编译器/解释器的设计。

选择使它们成为可选语言的语言设计师选择忍受歧义,以换取更大的语法灵活性。


7
@RobertHarvey异端!应该只有一种明显的方法。顺便说一下,在perl中只有一种方法可以做到这一点。

1
顺便说一句-某些语言在语法上通常有相当多的冗余,因此在实践中使分号为可选仅是偶然的。就是说,我认为分号是删除冗余的错误部分-我非常喜欢Haskell,在其中您可以放掉括号和逗号作为参数。好的,您也可以在Haskell中删除分号,但这与Javascript并不是一回事。
Steve314

2
IIRC的问题是它们不适合形式模型,但解析器生成器不会产生良好的错误消息。也就是说,他们对常见错误的了解有限,而手写解析器可以获得更有用的错误消息。例如,Gcc曾经将野牛用于C语法。同样,问题在于“边缘情况”不是形式上的边缘情况,而是软边缘情况-即对于解析器来说AST是清楚的,而对于人类来说AST是“清楚”的,但是他们不同意AST是什么样。
Maciej Piechotka

2
@Maciej Piechotka-我并不是要暗示在Haskell中,parens是可选的。我说的是放弃一些多余的东西作为语言设计的决定。关键是,在Haskell中,函数调用不使用括号或逗号。您可以将元组作为参数传递,但这仍然是元组的语法,而不是传递参数。Haskell(以及ML和其他人)“放弃”了函数参数的括号和逗号,因为在其他语言中也有这种通用约定(自Algol?),但是Haskell不会这样做。
Steve314,2013年

1
@Maciej Piechotka-当然,这从来都不是一个通用的约定-仅仅是因为Algol家族的语言做到这一点并不意味着其他语言相对于它定义了自己,所以我的“放弃”主张在这个意义上是错误的-但对于所有如今,C语言家族的语言有点像那样。
Steve314

15

JavaScript向我们展示了这是一个非常糟糕的主意。例如:

return
0;

在C中,它返回的值为0。在JavaScript中,这是返回的,undefined因为在return语句之后插入了分号,除非您碰巧知道自动分号的插入细节,否则代码中断的原因并不清楚。


1
@delnan:Python并非看起来像C。众所周知,它基于缩进,因此高度面向行,并且不需要分号。从技术上讲 JavaScript 确实需要它们。它会在发现一个缺失的情况时插入一个,将看起来像一个语法有效的语句转换为两个语义完全不同的不同语句。
梅森·惠勒2013年

7
这不是一个坏主意,这对那些尝试使用JavaScript而又不花时间去学习自动分号插入的人来说是一个困惑。也许不用说“这是一个非常糟糕的主意”,而是可以更准确地说:“使分号成为可选选项,这会给那些不愿意学习所有细节的程序员带来陷阱”。
TehShrike

4
@delnan:令人惊讶的原因是JavaScript通常不会在行尾插入分号,除非要修复否则无效的程序。After return是少数情况下JavaScript会插入分号的情况之一,即使没有该程序程序也将有效。(但是,当然,这破坏了梅森·惠勒的观点。问题不是分号是可选的,而是规则不一致。)
ruakh

6
@TehShrike:将分号设置为可选选项会为所有程序员带来陷阱,因为它会随意解释拼写错误,而不是询问您的意思。每个人都不时打错字。
2013年

1
javascript已显示其可选分号的实现存在缺陷。这并不表明可选分号本身就不好。
CodesInChaos

4

它在某种程度上简化了语法和解析器,使分号成为必需。从本质上讲,它允许词法分析器转储包括换行符在内的所有空白,并且解析器根本不必担心它。

另一方面,一旦您开始想告诉解析器有关空格的信息,将分号设为可选就不难了。您通常可以将它们与whitespace令牌一起打包,并且解析器可以很好地处理它。

例如,尝试将分号插入以下一系列C语句中。

functionCall(3, 4) 9 + (3 / 8) variable++ while(1) { printf("Hello, world\n") }

尽管有一些古怪的事情您不再可以做,例如while(1);,但现代解析技术相对容易地确定没有特定分隔符的语句在何处结束。即使您仍然想允许使用这些奇怪的东西,也可以使newline_or_semicolon非终结符变得不那么困难。


当C最初于1970年代初期开发时,需要使用语句终止符来简化编译器。到90年代中期,开发Javascript时,它已不再是一个问题。
肖恩·麦克索明

3

分号在语法中很有用,有两个原因。首先,它使您可以将长语句分成多行,而不必使用令人讨厌的连续字符(我在说的是Fortran和Basic)。其次,让语法分析器有一种方法可以在语法由于拼写错误而真正复杂化时“放弃”解析。仿照Karl Bielefeldt的例子,

functionCall(3, 4) 9 + (3 / 8) variable++ while(1) { printf("Hello, world\n") }

假设您输入了一个额外的开放括号:

functionCall((3, 4) 9 + (3 / 8) variable++ while(1) { printf("Hello, world\n") }

现在错误在哪里?如果您有分号,则解析器更容易放弃第一个分号。如果需要,它甚至可以在分号后继续解析。

functionCall((3, 4);  <- something is wrong here. emit error and keep going.
                      9 + (3 / 8); variable++; while(1) { printf("Hello, world\n"); }

现在,解析器更容易报告错误,并且更容易找到发生错误的行/列。


1
Fortran和Basic至少已适当选择了行继续标记(分别为&和_)。对于纯粹的“”妈呀,他们在想什么”,没有什么比FoxPro中要继续行,你使用一个分号。
DougM

2

分号并不总是像您在问题中提到的那样全有或全无。例如,Lua的语法经过精心设计,可以采用自由形式(可以忽略所有空格,包括换行符),但也不需要使用任何分号。例如,以下程序是等效的:

--One statement per line
x = 1
y = 2

--Multiple statements per line
x = 1 y = 2

--You can add semicolons if you want but its just for clarity:
x = 1; y = 2

0

除了所有的设计和构造,我相信很多程序员来自不同的背景,有些程序员学会了使用分号,有些则没有。许多新兴语言不需要分号但仍允许分号存在。我认为这可能只是一种方法,它可以使更多的程序员学习如何使用这些新语言进行编码,而不必在开始时就放弃他们的习惯。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.