为什么大多数编程语言都不嵌套块注释?


18

据我所知,有几个人可以,但不是任何一个受欢迎的人。嵌套评论有什么不好的地方吗?

我计划将块注释嵌套在我正在使用的(小)语言中,但是我想知道这是否是个坏主意。


重新回答几个问题:哦,这很有道理=)然后,我完全在做嵌套块注释;尽管我确实有一个单独的词法分析阶段,但这不是SK-logic所描述的限制排序。

@Vuntic:如果您有一个单独的词法分析阶段,该阶段使用比正则表达式更复杂的内容,则可能会遇到性能问题。通过实施DFA,可快速轻松地使用RE。
David Thornley

它更早地捕获了更多错误,不允许嵌套

4
@David:...一点也不。实际上真的很快。
amara

我建议,如果要允许嵌套注释,则允许对开始注释标签进行标记,并要求如果这样对开始注释标签进行了标记,则其结束注释标签必须进行相同的标记。这样可以快速识别不平衡的开始/结束标签,并避免因未检测到不平衡标签而导致错误的可能性。
2014年

Answers:


6

还没有人提到一件事,所以我要提及:嵌套注释的愿望通常表明程序员做错了。

首先,让我们同意,程序员只能看到“嵌套”或“非嵌套”的时间是程序员编写如下结构的东西:

do_something();
/* comment /* nested comment */ more comment */
do_something_else();

现在,这种事情什么时候在实践中出现?当然,程序员是不会被写入嵌套评论说,从字面上看起来像上面的代码片段!不,实际上,当我们嵌套注释(或希望我们可以嵌套它们)时,这是因为我们要编写如下内容:

do_something();  /* do a thing */
/* [ajo] 2017-12-03 this turned out to be unnecessary
do_something_else(); /* do another thing */
*/

这是坏的。这不是我们(作为语言设计师)想要鼓励的模式!编写以上代码段的正确方法是:

do_something();  /* do a thing */

该“错误的”代码,该错误的开头或其他内容不属于代码库。它充其量属于源代码管理历史。理想情况下,您甚至永远都不会写错代码,对吗?而且,如果错误的代码在这里达到了目的,则可以通过警告维护人员出于某种原因而不要恢复它,那么,这可能是写得好且有意的代码注释的工作。仅仅留下一些可以做X但被注释掉的旧代码来表达“不要做X”,并不是阻止人们执行X的最易读或有效的方法。

所有这些都归结为您之前可能已经听说过的简单经验法则:不要注释掉代码。(搜索这句话会变成一个很大 意见 一致。)

在您提出以下要求之前:是的,诸如C,C#和C ++之类的语言已经为程序员提供了另一种 “注释”大型代码块的工具:#if 0。但这只是C预处理程序的一种特殊应用,它本身就是一个庞大而有用的工具。要使一种语言支持条件编译,#if又不支持,实际上将是极其困难和特殊的#if 0


因此,我们确定嵌套注释仅在程序员注释掉代码时才相关。并且我们已经建立(通过许多有经验的程序员的共识),注释掉代码是一件坏事。

要完成三段论,我们必须接受语言设计者对推广“好事物”和阻止“坏事物”的兴趣(假设其他所有条件都相同)。

在嵌套注释的情况下,其他所有条件都是相同的-您可以放心地忽略那些低调的答案,这些答案声称解析嵌套/*对于解析器而言将是“困难的”。(嵌套/*并不比嵌套难,嵌套(几乎是世界上每个解析器都需要处理的。)

因此,所有其他条件相同,应该在语言设计使它容易嵌套注释(即注释掉的代码),或难吗? 回想一下,注释掉代码是一件坏事。

优质教育


脚注。请注意,如果您不允许嵌套注释,则

hello /* foo*/bar.txt */ world

是一种误导性的“评论”,等同于

hello bar.txt */ world

(这很可能是语法错误)。但是,如果您确实允许嵌套评论,那么

hello /* foo/*.txt */ world

是一种误导性的“评论”,等同于

hello

但注释始终一直打开到文件末尾(这几乎肯定是语法错误)。因此,这两种方法都不太容易出现无意的语法错误。唯一的区别在于它们如何处理注释掉的代码的有意反模式。


1
基于简单的事实,我有不同的看法-我什么都看不到(您也没有看)。因此,尽管诸如“不要注释掉代码”之类的黄金法则看起来不错,但生活却有自己的道路。在这种特殊情况下,当我测试一些新功能并不得不逐步引入一些代码时,我经常将其作为开关来执行,因此我注释掉了代码,然后越来越少地注释了代码,最后我有了工作可以删除所有注释(通过代码)。我的完美语言当然会支持嵌套注释:-)。
greenoldman

@greenoldman:大多数语言都没有可嵌套的注释,但是它们具有“删除代码块”的某些实际功能,该功能比“留下评论”功能少用。C #if DEAD是规范的和最佳设计的示例。在许多语言中,您只需将无效代码包装为即可if (DEAD)。在许多IDE中,您实际上可以删除无效的代码,并在需要时依靠Ctrl + Z和/或版本控制将其取回。留下注释,文档字符串,无论其文本是一堆无效代码,还是可读性最差的选择。
Quuxplusone

11

因为大多数实现都使用单独的词法分析和解析阶段,并且对于词法分析,它们使用的是普通的旧正则表达式。注释被视为空白-即忽略的标记,因此应完全在词法分析中解决。这种方法的唯一优点是解析速度。许多缺点包括语法上的严格限制(例如,需要维护一组固定的,与上下文无关的关键字)。


3
我对当今的“大多数”意见不一。当然,这是传统的方式,但是我知道对于C,EDG结合了预处理器,词法分析和语法分析,而且我怀疑GCC和Microsoft也会这样做。好处是它允许您在需要时单独实施它们。
Andrew Aylett

Clang也一样。但这只是现有流行语言编译器的一小部分。
SK-logic

@Neil Butterworth,看看mcs,javac,gcc(是的,它对词法分析器进行了后修补,但仍然是专用的词法遍历),clang(与gcc相同),dmd,fpc等许多其他内容。
SK-logic

没有人会在任何非平凡的编译器的词法处理中使用正则表达式。
诺基亚

@Nuoji-对于不平凡的-当然。但是那些依靠flex和类似工具的人却可以。
SK-logic

7

制作可以处理嵌套注释的词法分析器是完全有可能的。当它在吃空格时,看到/*它可以增加一个深度计数器,当看到时可以减少它*/,当深度为零时停止。也就是说,我已经完成了许多解析器,但从未找到嵌套注释的充分理由。

如果注释可以嵌套,则不利之处是很容易使它们的末端不平衡,并且除非您有高级编辑器,否则它会无形地隐藏您认为存在的代码。

不嵌套的注释的优点如下:

/*
some code
more code
blah blah blah
/**/

您可以在其中删除或添加第一行(一行编辑)来轻松地对代码进行注释或注释。当然,如果该代码本身包含注释,则除非您还允许//在其中使用C ++样式的注释,否则这将中断。所以这就是我倾向于做的。


1
//注释也是C99风格的。
JAB

或者,语言可以指定注释开始为/*$token,其中identifier任何字母数字标记为,注释结束为token$*/。对于令牌生成器而言,包括代码以验证每个结尾注释标记是否包含与其匹配的起始注释块正确的令牌,将相对简单。
超级猫

5

由于没有其他人提及它,因此我将列出一些支持嵌套注释的语言:Rexx,Modula-2,Modula-3,Oberon。尽管这里有很多关于难度和速度问题的抱怨,但似乎没有一个大问题。


4
我要添加的内容:弗雷格(Frege)Haskell
Ingo,

也受Scala支持。
Matt R

4

嵌套块注释的一个好处是,您可以轻松注释掉大部分代码(嗯,几乎,除非您在字符串常量中包含块注释结束序列)。

另一种方法是,如果有支持它的编辑器,则在行注释开始序列前添加一行。

Haskell嵌套了块注释,但是大多数人似乎没有注意到或抱怨它。我猜这是因为不希望嵌套注释的人倾向于避免使用它们,因为这将是其他语言中的词汇错误。


3

支持嵌套的块注释会使解析器复杂化,这不仅需要更多工作,而且可能会增加编译时间。我想这不是一种语言非常需要的功能,因此最好花时间和精力进行其他改进和优化。

在我看来,在设计任何东西时,简单总是一件好事。请记住,添加功能比删除功能要容易。一旦允许嵌套注释并且在那里有程序在使用它,您将无法在不破坏兼容性的情况下将其删除。


1
+1表示“比添加功能更容易添加功能”。
R..

3
一旦您禁止嵌套评论,您也将无法允许它们,因为它会破坏此类评论:/*/**/
RiaD

2

一个可能的原因是嵌套注释必须由解析器处理,因为词法分析器中常用的正则表达式不支持递归。lexer可以将简单的空格消除为空白,因此以这种方式实现起来更简单。


3
这不是“味道”。正则表达式中的“常规”一词固有地排除了递归。
R..

3
@R:当然,在数学上。但是在编程中,我们称之为正则表达式的东西确实支持递归。
阿马拉

问题是:这甚至是问题吗?大多数语言已经必须处理嵌套括号。仅举几例:Lisp,C,Java,Python,Ruby,Perl。
Thomas Eding

嵌套括号是可以的,因为括号内的内容与外面的内容相同:普通标记。在注释中,您没有标记,只有文本。您需要能够匹配开始和结束注释标记,以便您知道“ int”是类型还是注释中的单词。(特别是如果您消除了词法分析器中的注释。)
Alan Shutko 2014年

2
@ThePopMachine:我确定我说的话,正则具有定义的形式含义,而不是您使用的含义,并且为此选择了“正则表达式”中的“正则”。非递归是其定义的结果之一。
R ..

-1

谁知道?我猜是因为支持嵌套注释需要更多工作-您必须维护某种堆栈,并且因为它会使语言语法复杂化。


-1

嵌套的注释意味着解析器需要额外的工作。通常,当您看到注释的开始时,您将忽略一切,直到注释结束。为了支持嵌套注释,您还必须解析注释中的文本。但是,最大的问题是程序员必须小心正确地关闭所有嵌套的注释,否则将导致编译错误。正确实现编译器是可以完成的工作,但是作为程序员跟踪嵌套注释很容易出错和烦人。


3
-1:不正确。Sane解析器不是那样工作的。
阿马拉
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.