为什么c++语言的设计者一直在重复使用关键字?

Why do the C++ language designers keep re-using keywords?

本文关键字:关键字 语言 c++ 设计者 一直 为什么      更新时间:2023-10-16

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

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

c++ 11中新的"enum类"让我思考这个问题,但这是一个通用的语言设计问题。

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

不,这就是原因。

根据定义,

关键字无论在源代码中出现,总是被认为是关键字,因此它们不能用于其他目的。把某些东西变成关键字会破坏任何可能使用该标记作为变量、函数或类型名的代码。

C委员会采取不同的方法,使用_Reserved名称添加新的关键字,例如_Atomic, _Bool,然后他们添加一个新的头(<stdatomic.h>, <stdbool.h>)与一个更好的宏,这样你就可以选择是否包括头来获得名称atomicbool,但它不会自动声明,不会破坏代码,碰巧已经使用这些名称。

c++委员会不喜欢宏,希望它们是合适的关键字,所以要么重用现有的关键字(比如auto),要么添加与上下文相关的"关键字"(它们不是真正的关键字,而是"具有特殊含义的标识符",所以它们可以用于其他事情,比如override),要么使用不太可能与用户代码冲突的奇怪拼写(比如decltype,而不是广泛支持的typeof扩展)。

一些旧的语言根本没有关键字,特别是PL/1中

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

是一段合法的代码,但是完全不可读。(还可以将APL作为一个主要编写编程语言的例子,几个月后阅读它是完全神秘的,即使是代码的原作者)。

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宏,而像这些同源语言中的宏非常不同,因为在ast上操作,与C或c++中原始的文本替换机制…)允许重新定义现有的关键字;另请阅读卫生宏。但这可能会使源代码在几个月后变得难以理解。

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

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

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

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

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

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

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

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

也就是说,一个关键字只能用于一个任务。