【问题标题】:Why do the C++ language designers keep re-using keywords?为什么 C++ 语言设计者不断重复使用关键字?
【发布时间】:2015-09-24 09:12:48
【问题描述】:

支持重复使用短关键字(并添加与上下文相关的含义)而不是仅仅添加更多关键字的主要论点是什么?

您只是想避免破坏可能已经使用提议的新关键字的现有代码,还是有更深层次的原因?

C++11 中的新“枚举类”让我想到了这一点,但这是一个通用的语言设计问题。

【问题讨论】:

  • override 不是关键字,而是具有特殊含义的标识符。根据定义,关键字始终是关键字,不能用于任何其他目的。
  • @usr,对,但问题被标记为c++11,v.oddou 在 C++ 的上下文中非常具体地谈论了 C++ override keyw^W 标识符(“override 是现在是关键字”)。
  • 不,我的意思是 C++ 标准中的定义,它说“表 3 中显示的标识符保留用作关键字(也就是说,它们在阶段 7 中被无条件地视为关键字)除了在属性标记中(7.6.1)“(所以实际上它们可以用于其他目的,但仅限于属性内部。和字符串文字内部。但除此之外,罗马人为我们做了什么?)
  • 我已将标题编辑为特定于 C++ 并投票决定重新打开。 SO 用户可能对此有不同的看法,但 C++ 委员会没有。他们有一个长期的、有据可查的关于添加新关键字的政策,所以基于事实的答案是完全可能的(并且已经给出!)

标签: c++ c++11 keyword language-design


【解决方案1】:

您只是想避免破坏可能已经在使用提议的新关键字的现有代码,还是有更深层次的原因?

不,就是这个原因。

根据定义,关键字总是在源中出现的任何地方都被视为关键字,因此它们不能用于其他目的。将某事设为关键字会破坏任何可能将该标记用作变量、函数或类型名称的代码。

C 委员会采用不同的方法并使用 _Reserved 名称添加新关键字,例如_Atomic_Bool,然后他们添加了一个新的标题(<stdatomic.h><stdbool.h>)和一个更好的宏,这样你就可以选择是否包含标题以获得名称atomicbool , 但它不会自动声明,也不会破坏恰好已经使用这些名称的代码。

C++ 委员会不喜欢宏,并希望它们成为正确的关键字,因此要么重新使用现有的(例如 auto),要么添加与上下文相关的“关键字”(它们不是真正的关键字,而是“具有特殊含义的标识符”,因此它们可以用于其他事物,例如override)或使用不太可能与用户代码冲突的奇怪拼写(例如decltype而不是广泛使用的支持typeof 扩展)。

【讨论】:

  • 我认为 C++ 委员会不喜欢为此目的使用宏的原因之一是 C 的想法在 C++ 中行不通,因为在 C++ 中允许任何标准头文件包括任何其他。因此,即使您没有包含<stddecltype> 或其他任何名称,您现有的将decltype 用于其他目的的代码也可能会中断,因为<vector> 引入了宏。由于委员会一般也不喜欢宏,我怀疑是否有兴趣通过限制哪些标准标头可以相互包含来定义他们摆脱这种尴尬的方式。
  • 另外,有时委员会会继续在语言中添加std::complex<float>::operator""if(float)
  • @SimonRichter,但这不会破坏任何东西,因为它重用了一个关键字,用户无论如何都不能将其用于标识符。并且为那个糟糕的运营商建议的替代名称!
  • wrt to override and final Why are override and final identifiers with special meaning instead of reserved keywords? 也是相关的。它只是为您已经说过的内容添加了更多细节。
  • 您想要避免破坏现有代码并不是“只是”。不破坏现有 C++ 的数十亿行代码对 C++ 标准委员会及其数百万用户来说非常重要。见 stroustrup.com/C++11FAQ.html#specific-aims>
【解决方案2】:

一些旧语言根本没有关键字,尤其是PL/1 where

IF IF=THEN THEN BEGIN;
  /* some more code */
END;

是一段合法的代码,但完全不可读。 (也可以查看 APL 作为 write-mostly 编程语言的一个例子,几个月后阅读它是完全神秘的,即使代码的原作者也是如此)。

C 和 C++ 语言家族有一组由语言规范定义的关键字。但是有非常广泛使用的语言具有数十亿的遗留源代码行。如果您(或他们的标准化委员会)添加一个新关键字,则有可能与某些现有程序发生冲突,并且正如您所猜测和其他人所回答的那样,这很糟糕。因此,如果标准添加例如 enum_class 作为新关键字,很可能有人已经将其用作标识符,并且该实体会不高兴(在采用新的 C++ 标准时必须更改其代码)。

众所周知,C++ 的解析速度很慢(特别是因为像 <vector> 这样的标准头文件需要提取数十万行源代码,并且因为模块还没有在 C++ 中,并且因为语法非常模糊) ,所以使解析器复杂化以处理新语法并不是什么大问题(无论如何解析 C++ 总是很糟糕)。例如,GCC 社区在新的优化上比在新的 C++ 特性上更努力(显然,C++ 标准库的最新特性比解析新语法需要更多的工作),即使从 C++03 跳转到 C++11这是一个巨大的飞跃,需要在 C++ 前端进行大量工作。对于 C++11 到 C++14 的跳转,情况并非如此。

其他一些语言(例如,一些 Lisp 方言,例如 Common Lisp 和一些 Scheme,您可以在其中重新定义 letif 宏,以及在 homoiconic 中重新定义 macros 这样的语言是 非常不同,因为在 ASTs 上运行,与 C 或 C++ 中粗略的文本替换 mechanism...) 允许重新定义现有关键字;另请阅读hygienic macros。但这会使源代码在几个月后变得难以理解。

【讨论】:

  • Fortran 固定格式源代码对于打字不好的人来说更有趣。 do 100 i = 1, 5 是循环的开始,但 do 100 i = 1. 5 是赋值语句。空白被忽略,所以do 100 Ido100i 是同一个变量。
  • PL/1 的有趣部分之一。只有当你感觉真的很残忍时才会这样做。如IF IF=THEN THEN THEN=ELSE;否则,否则=那么; .快乐时光。
  • letlambda 重新绑定Scheme 关键字并不算太糟糕。当关键字被宏识别时,事情变得危险。此类宏往往表现不佳,因此不经常使用。
  • 至少在 Common Lisp 中,符号从它们所绑定的包中获取它们的含义,所以如果未来的 CL 标准添加了符号,它只需将它们放在与 COMMON 不同的包中-LISP(别名 CL)包。 (defpackage my-library (:use :cl)) 例如,cl21.org 重新定义了大部分语言,但每个包都可以决定是“使用”包 CL 还是 CL21,因此与现有代码没有冲突。这有点像在每个 C/C++ 文件中都有一个声明,比如 using standard c90; 可以追溯到 25 年前。
【解决方案3】:

我认为这主要是因为添加关键字会破坏在其他上下文中碰巧使用此关键字的现有代码,正如您所建议的那样。

【讨论】:

    【解决方案4】:

    您只是想避免破坏可能已经在使用提议的新关键字的现有代码,还是有更深层次的原因?

    根据定义,关键字是不能在其他任何地方使用的特殊标记;因此,引入关键字会破坏任何碰巧使用具有给定拼写的标识符的代码。

    某些语言使用术语上下文关键字来指代仅在特定上下文中被解释为关键字的拼写。如果以前在此上下文中不能使用“百搭”标识符,则可以保证引入上下文关键字不会破坏现有代码。例如,由于在函数签名的右括号之后不能立即出现标识符,因此可以在此处引入所谓的上下文关键字(例如overridefinal)。

    另一方面,在以前允许使用任何标识符的地方,添加关键字会带来风险。例如:

    • struct H { my_type f; enum { g }; };:使用enum class 而不是新关键字是因为在这种情况下,任何新词都可能被错误地视为数据成员声明的开始;只有一个关键字是明确的(在 LL(1) 中),并且引入一个新关键字可能会破坏代码。
    • void h() { my_type f; auto x = g(); }:使用auto 而不是新关键字是因为任何新词都可能与现有类型发生冲突。这仍然是一个令人惊讶的选择,因为它已经是一个可以在这个位置在 C 中使用的关键字(默认为 int 类型),但它的含义被改变了(理由是它的使用概率很低)。

    正如一些人所提到的,语言可以设计成完全没有关键字(Haskell 非常接近),或者以一种可以无缝引入关键字的方式(例如,如果每个声明都以关键字开头,那么引入一个新的关键字)关键字不能冲突)。与没有这样做的 C 和 C++ 以及许多类似 C 的语言相比,这种情况发生了。

    【讨论】:

    • auto 关键字不能在该上下文中使用,因为没有显式类型的声明是非法的。 auto int x = 42; 是旧规则下的有效声明。 auto x = 42; 是旧规则下的语法错误,相当于新规则下的int x = 42;。但是,是的,这两个上下文的相似性可能会令人困惑(如果不是因为旧意义上的 auto 几乎从未使用过。)
    • @KeithThompson:抱歉,问题来自compatibility with C,它允许auto i = 0;
    • 正确 -- 但仅限于 C90 及更早版本。 C99 删除了“隐式int”规则,使auto i = 0; 非法。有趣的是,在 C99 之前的 C 中,auto i = 0.0 使 i 成为 int,而在 C++11 及更高版本中,相同的声明使 i 成为 double
    【解决方案5】:

    “少即是多”的错误热情。人们认为(错误地)通过使用更少的关键字,程序员将不得不学习更少并且可以更快地提高生产力。但这只会造成语法上的混乱。

    “真正的 Perl 程序员更喜欢视觉上不同的东西。” ---- 拉里·沃尔

    换句话说,只为一项任务使用关键字。

    【讨论】:

    • 我不相信这是原因。您是否有任何证据表明确实如此,或者委员会中的任何人认为使用较少的关键字会使语言更容易学习?据我所知,重用现有关键字的整个原因是为了避免破坏现有代码。众所周知,重用static之类的事情会导致额外混乱,但这是值得付出的代价。
    • @GOTO0 好点。我看到这个问题在这个答案发布 2 小时后被限制在 C++ 中。即使在编辑之前,我也可以理解反对票 - 引用是与问题所问内容相反的证据,但作为语言设计者做出错误决定的证据。这表明没有充分的理由做出这个设计决定,而其他答案表明情况并非如此。
    • @trichoplax:所以不要不同意这群人。上次我会读堆栈。
    • 如果您查看原始问题的历史,它开始是一个模糊的“人们为什么做事”。这最终被关闭了,因为它是基于意见/广泛的(没有人能回答为什么每个语言设计师都会做某种事情)。然后(围绕示例)将其缩小为关于 C++。有趣的是,C++ 重用关键字的原因既狭隘又有据可查,因此重新提出了这个问题。在原始问题的上下文中,您的答案很糟糕(不要做 X 是对为什么 X 的糟糕回答?)。在 C++ 问题的上下文中,您的答案很糟糕。因此,投反对票。
    • @GOTO0 Larry Wall 对 C++ 重用关键字的原因并不权威。有人认为重用关键字是个坏主意,这与为什么语言重用关键字的问题无关,甚至在它被缩小到 C++ 之前。我承认没有人在其他答案中引用标准化会议的会议记录或提案的官方会议记录。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-07-31
    • 1970-01-01
    • 2021-08-15
    • 2012-08-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多