(轉貼) 专访Bjarne Stroustrup (C/C++)
专访Bjarne Stroustrup
Elden Nelson:如果您现在有机会从头设计C++语言,您会做些什么样的改变?
Bjarne Stroustrup:当然,你永远都不可能重新设计一种语言,那没有意义,而且任何一种语言都是它那个时代的产物。如果让我今天再设计一种语言,我仍然会综合考虑逻辑的优美、效率、通用性、实现的复杂程度以及人们的喜好。要知道人们的习惯对于其喜好有着巨大的影响。
现在,我会寻找一种简单得多的语法 — 它可能与人们对“熟悉”和“简单”的混淆认识相悖,我会把对类型系统的侵犯限制在极少的语言构造里,并且用明显“丑陋”的语法来标识它们。(就象我对对新风格的“转型”的处理,比方说,reinterpret_cast(p)就是一个用来描述一种“丑陋”操作的“丑陋”记号)。这样可以很容易地禁止不安全的操作。
我还会把核心语言的体积搞得尽可能小一些,包括类和模板的关键的抽象特性,而把很多其它的语言功能放在库里来解决。当然我也会保证核心语言足够强大,使得那些库本身也足以用此核心语言来产生。我可不希望标准库的编写者依赖于普通用户无法使用的额外的语言特性。我还努力使核心语言的定义更加精确。
最重要的是,我会在该语言被广泛使用之前尽可能维持一个很长的酝酿期,这样我就可以根据来自真实用户的坚实反馈对它进行改进。这可能是最困难的,因为一旦有什么东西明显出色并且前途光明,它就会被广为使用,此后进行任何不兼容的修正都将变得极其困难。
我相信这些思想与我当初设计C++时的理念是非常类似的,它们同样也指引着一、二十年来C++的不断演化。当然,我认为现在还没有什么东西能让我觉得象是“完美的语言”。
Elden Nelson:当您设计C++语言时,您是否借鉴了其他崭露头角的对象语言(例如Modula-2)的思想?
Bjarne Stroustrup:在C++的设计过程中,我吸取了C、BCPL、SIMULA、ALGOL 68、Ada、ML以及其他一些语言的思想。当时我知道Modula-2,还知道至少一打别的语言,但我回想不起来Modula-2对我产生了什么直接的影响。
为了回答“为什么C++会是这样(以及为什么不这样)”之类的问题,我撰写了《The Design and Evolution of C++》一书。也就是说,这本书记录了导致C++现状的设计决策、原则以及折中权衡,我推荐对此类问题感兴趣的读者阅读这本书。
Elden Nelson:您预期对C++做哪些增强,会不会删掉一些东西?
Bjarne Stroustrup:很不幸,虽然有一些东西真的可以扔掉,但恐怕很难删掉任何东西。第一个应该抛弃的东西就是C风格的转型机制和类型截断转换(narrowing conversions)。就算不禁止,编译器的作者们至少也应该对这种行为给与强烈的警告。我希望能用标准库中的vector之类的东西彻底取代数组,但这显然是行不通的。不过如果程序员们能主动在所有应用编程中使用vector来代替数组,就会立刻受益匪浅。关键是你不必再使用C++中最复杂难缠的技巧了,现在有优秀得多的替代方案。
我没打算去掉任何大的特性。特别是那些把C++与C区别开来的主要特性恐怕没法风平浪静地被抛掉。通常问这些问题的人是希望我挑出诸如多继承、异常、模板等机制来接受批判。所以在此我想大声讲清楚,我认为多继承机制对于一门具有继承机制的静态类型语言来说是必需的,异常机制是在大系统中对付错误的恰当的方法,模板机制对于类型安全、优雅和高效的程序设计来说不可或缺。我们可以在语言细节方面对这些机制吹毛求疵,但在大的方面,这些基本概念都必须坚持。
现在我们仍在学习标准C++,也正在标准所提供的特性基础上发展出更新且更有意思的编程技术。特别是人们刚刚开始使用STL和异常机制,还有很多高效强大的技术鲜为人知,所以大可不必急匆匆地跑去增加什么新机制。
我认为当前的重点是提供很多新的、比以前更加精致的且更有用的库,这方面潜力巨大。例如,如果有一个能被广泛使用的、更精致的支持并发程序设计的库,那将是一大福音 — C风格的线程库实在不理想。我们也就可以与各种其他的系统比如SQL以及不同的组件模型更好地契合起来。在优雅高效的库的开发方面,数值计算领域的人们看起来已经走到了前面(例如Blitz++、POOMA和MTL,请访问www.research.att.com/~bs/C++.html)。
有了足够的经验之后,我们就可以更好地决定什么能够(也应该)被标准化。
Elden Nelson:我们正不可避免地走向一个以Web为中心、分布式计算为主流的时代。那么您觉得C++还能维持其地位吗?程序员们可不可能把若干种专用语言(比如Perl、Javascript)综合运用以彻底取代某一种通用语言?为了配合新的计算模式,C++或标准库应该做出怎样的调整?
Bjarne Stroustrup:从来没有哪一种语言能适合所有的工作,恐怕以后也不会有。实际系统通常是用多种语言和工具构造起来的。C++只是想成为若干语言和工具中的一个,当某些专用语言在其领域里特别突出时,它们可以与C++互为补充。也就是说,我觉得如果大多数现在的专用语言能借助特定领域的C++库共同工作的话,它们会表现得更出色,而脚本语言通常导致难以维护的代码,这或许跟语言选择关系不大,可能更是因为急着想将产品尽快推向市场。如此一来,哪还有什么精力考虑程序结构、伸缩性和可维护性方面的问题?
我不敢肯定未来的代码是否真的会以Web为中心,就算是直接处理Web的系统也主要是由处理本地资源(比如IP连接)的程序模块构成的。
地理上的分布性以及服务器软件对于并发机制的高度依赖对于系统的构建者来说的确是个挑战。针对上述问题的一些库已经出现,也许我们将会看到它们最终得以标准化。当然,一些原语操作和保证规则应该被加到核心语言中以提供对这些库的更佳支持。
总的来说,对于Web和网络,我们非常需要一个真正的系统/网络级的安全模型。指望下载的“以JavaScript之类的语言编写”的脚本来实现这个模型无异于痴人说梦。请注意,我也并没有宣称C++提供了这个问题的解决方案。C++被设计为对所有系统资源提供高效的访问,而不是为了防止被欺骗。
Elden Nelson:您认为C++未来的走向如何?在接下来的10年里它会衰落吗?或者基本保持现状,或者演化为某种不一样的东西?
Bjarne Stroustrup:C++有着极美好的未来。用它你能写出伟大的代码。不管被多少敌意的宣传所攻击,C++仍将是开发高性能、高复杂度系统的最佳语言。据我所知,还没有哪种语言能象C++这样,将通用性、效率和优雅有机结合。
我没看到C++有衰落的迹象。在我能预见的未来里,它的用途还会不断增长。当然,在未来的十年里我们会看到一些变化,但不会象这篇访谈中的这套问题所暗示的那么多。跟每一种语言一样,C++也会不断演化。“语言专家们”要求改进的喧嚣声震耳欲聋,但是系统开发者们的基本请求是保持稳定。
C++会改进,但这些改进将是“经验”的结果而非对“狂热”的反应。为了更高效地使用一些新的编程技术,比如通用编程技术,可能会增加一些小特性。会有大量的库涌现,我预期会出现一些新颖的便利设施以支持更好的库。我希望新的扩展主要集中在支持抽象方面的一般特性,而不是为支持某些特殊任务的特定机制。
打个比方,属性(properties)是一个有用的应用层的概念,但我不认为在一种通用编程语言中有它的容身之地。用标准C++的一组类可以很容易地支持这一概念。如果我们感觉那族类对于“属性”这一概念的支持不合口味,我们也不应该立刻跑去在语言里增加属性机制,而是仔细考虑如何改进类和模板以帮助库设计人员尽可能接近“属性”这个概念。也许通过改进函数对象机制能够给这个问题一个满意的答复。
为了使C++在接下来的十几年中保持生命力,很基本的一点就是不要让标准C++赶什么学术或商业时髦。人们要求增加的特性中很大一部份通过使用现有的标准C++开发新库的方式都可以实现。还有,事实上人们渴望得到的很多奇妙的特性已经包含于标准C++之中,并且被所有最新版本的编译器所支持。对许多程序员来说,提高代码质量的最佳途径不是追求什么语言扩展,而是静下心来品味最新的C++技术书籍。
Elden Nelson:对于当前脚本语言的兴旺态势您怎么看?特别是Python,与C++相比,它似乎提供了一种更简单的OO技术学习途径。
Bjarne Stroustrup:有些语言很不错。比如Python,我很喜欢。但是我认为你从不同的语言中学到的OO技术是不完全相同的。当然,每一个职业程序员都要通晓几门语言,并且应该意识到,在不同的语言之中,编程和设计技术有着显著不同。
在我看来,用脚本语言建造的系统与用C++那样的通用语言建造的系统大不相同。从两类语言中学到的技术区别明显。不存在“可以满足绝大多数高效系统构建所需”的公共OO技术子集。
Elden Nelson:有没有计划对标准C++语言进行扩充或改进,从而为分布式计算提供更好的支持?
Bjarne Stroustrup:没有,我也不认为有这个必要。用更好的库就差不多能解决问题了。充其量为了支持这类的库,我们可能会增加一些低级的“原操作(primitives)”或“保证(guarantees)”。
Elden Nelson:将来C++有没有可能定义一个可移植的二进制接口?
Bjarne Stroustrup:如果你说的“可移植”是指跨硬件和跨操作系统,我想答案是no。我们当然可以设计一个解释器或者虚拟机什么的,但这样一来,由于无法以最优方式访问系统资源,C++的能力就会受到削弱。我希望在不远的将来能够看见平台ABIs(platform ABIs)。例如,有人正在努力为Intel新的IA64架构定义C++ ABI(参见http://reality.sgi.com/dehnert_engr/cxx,http://developer.intel.com/design/ia-64/devinfo.htm),我想这些努力会得到用户社群的强烈支持。
能够把一台PC上不同编译器产生的代码连接(link)在一起是一件美妙的事。
Elden Nelson:您目前是否正在为其他新语言开展工作?
Bjarne Stroustrup:没有。我还在学习如何使用标准C++,并且进行一些分布式计算的试验。我认为编程本身远比编程语言细节有趣。我认为只有当你有一些东西无法用已有语言合理表达时,才需要考虑设计一门新语言。对我来说,绝大部分工作都可以通过C++很好地完成。
Elden Nelson:以“后知之明”的角度来看,您是否认为“使一个成员函数默认为非虚函数”是一个明智的决定?假设有机会改变,您会改变这个决定吗?
Bjarne Stroustrup:也是也不是。
使C++保持生命力的要素之一即是“零开销规则”:你无需为你不用的功能付出代价。使一个成员函数默认为非虚函数会违反这条规则,还会为“提供高效的具体类型(concrete types)”增加难度。对于那些认为“类”即为存在于复杂层次结构中的大家伙的人们来说,默认为virtual是显然的。一般来讲,虚函数不适合那些关键的小而具体类型,例如复数、points、vectors、lists,以及函数对象。对于这样的类型来说,如下方面至关重要:表达的紧凑性、基本操作的内联化、访问的直接性、堆栈的配置,还有对“重载函数不会对语义造成不希望的修改”的保证。
此外,如果默认为virtual的话,你将需要一个non-virtual或final关键字,而且当过度使用它时会导致扩展性问题。在语言设计里,的确没有免费午餐。
Elden Nelson:在您看来,经由IEEE执行的标准化过程对C++语言的完备性、灵活性以及能力等方面产生了怎样的影响?
Bjarne Stroustrup:对于C++来说,ISO标准化过去以和现在都是重要的。其重中之重在于,标准委员会为技术人员提供了一个探讨技术问题的“中立的舞台”。还有什么别的地方能够让来自于相互竞争的机构(比如Microsoft、IBM、Borland/Inprise以及Sun等)的用户和编译器编写者们出于对用户利益着想,坐到一起合作共事呢?ISO的工作是民主的,是以大多数人的意见为基础的。为了达成一致的意见是需要时间的,但这样的努力非常值得。否则将导致语言的定义只为某一家公司(或少数几家公司)的利益服务。
由ISO工作而形成的标准C++比以前任何版本的C++都更加接近我的理想。标准C++的“异常”与我自己定义的几乎相同,模板更具灵活性,名字空间和运行时类型信息也被添加进来。从对编程风格(你也可称之为“范型”)提供支持的角度来看,其余内容皆属于细节问题,自然而然,标准委员会工作的主要部分便是精确定义这些细节。
鉴于接近标准的编译器可以广泛获得,人们试验那些新功能的时机已经来临。在几年之前很多东西还没有成为现实,如今可以在实际应用中使用它们了。那些对于大多数人来说仅能在语言定义上看到的技术,现在已被开发出来。例如STL(标准库中容器和算法的框架)就是一个有意思的新技术的优秀资源。
当然了,在接下来的关键项目中,你不应该冲到最前面使用所有语言特性和所有新技术,但是,是开始学习新语言特性和新标准库并试验它们哪些适合你哪些不适合你的时候了。
假如需要文档资料,你可以通过ANSI以18美元购得C++标准(参见 www.research.att.com/~bs/C++.html),也可以免费获得接近标准的草案。但是,这份标准并不是教本。我向有一定经验的程序员推荐我的《The C++ Programming Language》第三版,这本书以更易理解的方式讲述了完整的语言和标准库,它还阐明了C++支持的很多基本设计和编程技术。然而,即便这本书也不适合初学者阅读,因此,请先浏览我的个人主页(www.research.att.com/~bs/)以了解我的写作风格和详细程度能否满足你的需要。
Elden Nelson:在不少流行领域,C++正渐渐失去光芒,因为它要求人们花很大的精力去对付一些很基本的工作,比如管理内存(因为没有垃圾回收机制),管理模块之间的依赖性(因为无法创建包(packages)),管理组件的版本。C++缺乏一些现代语言已经视为标准的特性,谣传中最酷的Java语言试图解决这些问题,那么解决这些问题是否会导致C++的发展背离其根本宗旨呢?C++应该怎样发展以保证我们在这种语言上的投资能有合理的回报,而不是被迫从头学用另一种语言?
Bjarne Stroustrup:我倒还没有注意到C++比以前用的少了,相反,我看到的指标表明C+的使用还在稳步上升。只不过这种基数很大的稳定增长以及在标准性、移植性和库方面的不断提高并没有造成什么具有欺骗性的新闻效应而已。我认为你所说的“失去光芒”只不过是市场营销和新闻意义上的现象。
如果你需要垃圾回收机制的话,你可以在C++应用程序中插入一个垃圾回收器。有不少免费的和商业的垃圾回收器已经在重要的实践中被证明非常出色(可以参见www.research.att.com/~bs/C++.html)。
如果你不想使用垃圾回收机制也没关系,你可以使用标准容器类,它们大大减少了对于显式分配和回收内存的需要。这样,通过使用现代的库所支持的现代的编程风格,你就能避免绝大多数内存管理问题。
同样的技术还可以用来避免一般资源的管理问题。并不是只有内存才会泄漏,线程句柄、文件、互斥锁、网络连接等都是重要的资源,为了建立可靠的系统,它们必须被正确地管理。如果你以为有了自动垃圾回收机制就可以解决所有资源管理问题,那你最好赶快从美梦中醒来。
C++提供了一些机制来管理常见资源。关键的手段 — 资源获取即初始化(resource acquisition is initialization)依赖于函数对象来管理生存期问题。语言中关于对象的部分构造规则和异常机制对这项技术提供了一般性的支持。关于异常处理技术的讨论,请参阅The C++ Programming Language (Special Edition) 的新附录“Standard-Library Exception Safety”,它也可以从我的Web站点访问到(www.research.att.com/~bs/3rd_safe0.html)。
某些语言的狂热支持者总是用讽刺的手法来描述C++,然而C++实际上要好得多。特别是我认为很多其他特性已经被吹嘘过度了,而在C++中,通常这些特性能够很容易地被模拟出来。相反,新语言总有一种“在损害一般性的情况下”添加新特性的倾向,这也是一门新语言从诞生到被接受为一种用于常见计算的有用的工具,其体积和复杂度通常会增加两到三倍的原因之一。
目前,使用C++的个人和组织可以进行的最佳投资就是去更好地理解标准C++和现代的C++设计和编程技术。大多数人使用C++的方式实际上停留在80年代中期的水平,甚至比那更落后。
精确区分语言和系统/平台之间的责任是一个困难的问题,我的观点是,它们之间应该有一个明显的分界线,并且,依赖关系应该尽可能地置身于语言之外,系统相关和系统依赖的库才是解决系统依赖性的地方,而语言并不是。
我不认为组件版本管理之类的问题应该由编程语言来解决,这是一个系统范畴的问题,在语言里应该通过提供用于系统访问的适当的库来解决。C++有这样的机制。解决这样的问题并不会违背我对C++所奉行的理念。但在另一方面,给C++增加很多特殊的特性会使C++偏离轨道,而且在保持可移植性和平台独立性方面也是一个倒退。
Elden Nelson:如果为库中某个基类定义一个派生类,要想覆写(override)基类的一个虚函数,你就必须得到这个基类的源代码,以便获知是否需要调用基类中该函数的实现代码,您是否认为C++类库在这方面有那么一些失败?
Bjarne Stroustrup:唉,造成某些C++类库的这种缺陷的原因是,其设计者认为必须将此问题定义到他们的库中,并且一些用户认为他们必须以这种方式来使用库。这真是差劲的设计,是对C++差劲的使用!
如果你不想依赖基类的数据或者代码,就不要把它们放到基类中,这正是抽象类的使命。考虑如下代码:
2{
3 public:
4 virtual bool empty() = 0;
5 virtual Element get() = 0;
6};
它为所有派生类提供了“Reader”功能的一个接口。Reader的用户完全不依赖于那些派生类的实现细节。尤其是当某个派生类的代码改动时客户代码并不需要重新编译。还有,用户可以同时使用Reader类的多种不同实现(也就是说,可以同时使用多个不同的派生自Reader的类)。
从1989年发布的2.0版起,抽象类就已被直接支持,并且这项技术/风格总是随时可用的。这些历史以及语言设计考虑在《D&E》中皆有描述,自然而然,The C++ Programming Language解释了在什么情况下以及该怎么使用抽象类。
随便说一句,通过继承一个抽象接口类,再继承某个类层次结构中一个具体类(以获得它提供的有用功能的实现代码),是多重继承的一个最简单、最明显的用法:
2{
3 // override virtual functions from Interface,
4 // implementing the overriding functions
5 // using facilities offered by Implementation
6 // Where needed, also override virtual functions
7 // from Implementation
8}
我认为抽象类是一项远远没被充分利用的C++特性。程序员总是设计层次深深的继承体系,还在基类中添加大量数据和代码。有时这么做是有道理的,但在大的系统接口设计中,你更需要的是程序不同部分间的独立性,由抽象类提供的纯粹的接口往往便是更好的设计选择。较老的C++库的另一个问题在于,其设计者还不能使用模板。有些情况下继承的使用毫无必要或缘于无知,因为将类型参数化更加合适。
Elden Nelson:为什么在C++中没有关键词“super”?
Bjarne Stroustrup:因为在C++中,它既非“必要”也不“充分”。
“super”之所以不必要,是因为Base::f这种符号允许程序员表达f是“Base的一个member”或是“Base的一个base”。
“super”之所以不“充分”,是因为你需要表达f来源于Base1而非Base2。
Elden Nelson:一些厂商已经或正在对他们的C++编译器进行修改,以支持平台相关的语言扩展。您对此有什么看法,您认为这会有什么作用?
Bjarne Stroustrup:我认为平台相关的语言扩展应该最小化,当必须进行扩展时,其设计应该局部化于库中。当然,比起我自己,平台供应商们倾向于认为要进行更多必不可少的扩展。他们还倾向于使扩展弥漫于应用代码之中,从而使用户很难更换供应商。身为一个注重可移植性的用户,我对这种套牢用户的伎俩表示遗憾。
出于用户的利益着想,理想状态必须是可移植的,且平台相关的代码应被隔离在应用代码的一些特别段落。可移植性,以及不因厂商的奇思异想而改变的语义,是一门标准语言比专有语言优越之处。我认为C++供应商们应该意识到这可以成为一个竞争优势,并将专有扩展及扩展所引起的冲击最小化。假如你想用Java和Visual Basic那样的专有语言,你知道到哪儿去找它们。
Elden Nelson:您对目前花色繁多的C++编译器有什么看法?请不要因为这是《Visual C++ Developers Journal》的采访而影响您的看法。
Bjarne Stroustrup:它们正变得越来越好。这包括所有C++编译器。我通常使用六种不同的C++编译器。几年前我是做不到这一点的,当时一些被广泛使用的C++编译器还不能完全满足我的需要。
我乐意让“这是《Visual C++ Developers Journal》的采访”的事实影响我要说的话。因为这正是鼓励微软更加遵循标准的绝佳场合!VC++已得到改进,但是凭微软所拥有的资源,还可以进一步提高符合标准的程度,并为核心语言特性和标准库提供更高质量的支持。例如,对于目前大多数C++编译器来说,关于模板的出错提示信息仍有较大改进余地。
在遵循标准方面,现在的情况比以前要好多了,但在VC++中,我们仍然不能使用模板友元和模板部分特化功能。我非常乐意看到有人实现了对模板的分别编译 — 从Cfront时代起,它就是一项我想用而无法用的重要功能。
如果VC++能为新手学用标准功能打开方面之门,那将是一件好事。下边是那个没什么实际价值的“第一个”程序:
2int main()
3{
4 std::cout << "Hello, new world\n";
5}
6
7
在我看来,略微提高投在标准库方面的资源,而不是提高投在专有扩展和专有功能方面的资源,将是微软帮助最大数量的程序员最廉价的方法。
通常产生的代码的性能挺好。基于用户社群不同的关注方面,各种编译器倾向于各有区别。我认为最重大的收益来源于对标准库的调整。例如,从一个istream中将一个字符序列读入一个string,就是一个值得优化的操作,不为别的,它可以避免程序员去摆弄诸如字符读取、显式缓冲、空间分配和指针之类的玩艺。举个例子,下面的代码既优雅又不失效率:
2string terminator = "endend";
3string s;
4while (my_input>>s && s!=terminator) vs.push_back(s);
请参阅我写的《把标准C++当作一门新语言来学习》一文中关于风格和效率的议题(我的“publications”页面有链接)。
Elden Nelson:标准C++并没有任何方式定义支持并发、持久化和基于组件的编程,这导致了互不兼容的、平台相关的框架(例如CORBA、DCOM和SOM等)的繁殖,所有这些都有违直觉、杂乱无章,这不正表明标准C++应该为并发(尤其是线程)和组件对象模型提供直接支持吗?
Bjarne Stroustrup:“并发”和“组件对象模型”无疑是摆在当今所有语言的设计者面前的巨大挑战。不幸的是,这些挑战往往出于政治原因而非技术因素,有太多的金钱使之走样。
用户的理想语言应该是一门直接支持广泛的并发需求并对组件这一通用概念提供良好支持的语言。在理想状态下,程序员不费吹灰之力即可建立起语言功能与给定的组件架构之间的映射,这是“保持应用程序与它们所运行的硬件和操作系统之间适当的独立性”的理想的一个现代表现方式。
这可能与“组件可通过任意编程语言编写并且组件都应设计为可被任意语言无痛复用”的理想相悖。组件模型的一些支持者主张,程序员应该考虑编程语言的可互换性,为给定的对象模型专门编写代码,此模型的基本元素在这些代码中高度可见。我并不赞同这一观点。然而,我猜测这两种理想可以达成一个极好的折衷。
在一个“幼稚”的程序员看来,一个被调用的组件就是一个美其名曰“抽象类”的东西:你从某处获得一个接口,然后通过一个句柄(handle)来使用它,正像你通过句柄、指针或是引用使用其他抽象类一样。这样便可以向用户整洁优雅地展示组件模型,无需显式使用语言扩展,也无需“幼稚用户”明确知道到底在用哪种组件模型。例如,一个句柄类可以带有一个string参数的服务名字:
此处的d208d恰巧是我办公搂下大厅的打印机的名字。
这样一来,使用与“通过标准I/O为用户屏蔽操作系统和硬件”完全相同的技术,便可为“幼稚用户”和大型程序的绝大多数模块屏蔽掉系统依赖性。“幼稚用户”应该永远无需显式处理组件模型的“魔法” — 比如唯一组件标识符(unique component identifiers)。更加复杂的使用需要更多的知识,更常需要编写平台依赖的代码,还可能不得不明确使用那些为支持某种组件模型而提供的语言扩展。这里关键之处在于,对组件模型的“曝光”可以而且应该是缓和的,还应依赖于此应用对模型所提供的功能进行直接操纵的需要程度。在大多数情况下,我希望扮演“幼稚用户”角色。
组件模型提供了很多东西,但目前它们与C++的“捆绑”迫使程序员为了使用它们而不得不做太多的工作,迫使程序员要对所使用的模型了如指掌,还常常从程序员手中剥夺了丰富的编程语言功能。由此便有这样一种趋势 — 鼓励程序员以该模型支持的所有语言的一个公共子集来编写代码。语言中立性所提出的需求并不意味着所有接口对于所有语言都必须可用。也就是说,并不要求必须以该模型支持的所有语言的最小公共特性集来表达接口。
当我编写C++程序时,我希望使用标准库中的vector、string、map以及list这样的C++便利设施,以便在组件之间进行通讯。我并不想降低抽象层次,转而使用int*、char*、void*以及转型操作(casts)。既然组件意味着可以应用于所有语言,因此,我既可以提供一个工作于较低层次的附加接口(使之为另一个抽象类,这正是适合用多重继承处理的一种情况),也可以其他语言方式编写例程以提供对我的C++抽象功能的存取。
别误会,我并不是说你今天就可以在你的机器上如此这般做事,我的意思是说,如果使用组件模型就有可能获得此等程度的优雅性和灵活性,并且,在尽量最小化系统相关的语言扩展“侵入”的前提下提供组件模型是可能的。我相信这应该是用户的理想。我将鼓励组件模型的供应商们出于其用户的利益而努力接近这个理想。目前C++的绑定物“侵入”程度过于严重,向用户暴露的组件模型细节过多。
自然而然,并发(concurrency)也将闪亮登场。我再次声明,以相对“非侵入”的方式在库上大做一番文章即可。在直接语言支持方面仅停留在原语级别,且大多数情况下对大部分用户来说不可见。
另一个需要解决的问题是安全性。我并非只意指类型安全,而是指对系统一致性的保证以及对资源访问的控制。我怀疑没有操作系统和组件模型的支持是做不到这一点的。这是一个热门研究领域。
Elden Nelson:那些业已存在的事实上的标准,比如pthreads,将有多大可能成为标准库的一个组成部分(虽然已拥有一个面向对象接口)?毕竟,C标准库的主要部分都是在考虑Unix的前提下设计的,而且其设计者并不试图保持平台中立。
Bjarne Stroustrup:这是某种“并发”支持进入标准的一个良好契机。平台中立性将会被严肃地解决,因为标准委员会的一个美妙之处在于它是由使用许多不同平台的代表组成,而且委员会是在“争取一致意见”的要求下运作的。
Elden Nelson:在另一次采访中,您将C的声明语法定义为“一个失败的尝试”。但是,这种语法结构已形成27年了(可能还不止),为什么您认为它是有问题的(撇开其麻烦的语法不谈)?
Bjarne Stroustrup:我正是因其麻烦的语法才认为它有问题的。能够表达诸如此类的想法是有益而且必要的:“p是一个指向一个数组的指针,此数组有10个元素,每一个元素皆为一个函数指针,被指向的函数接受两个整型参数并返回一个bool型值”,然而,
并非表达此意的一种明显的方式。实际上,我不得不使用一个typedef才能妥当表达:
2Comparison (*p)[10];
3
4
即便在此处,包围指针的圆括号也似乎是多余的,但事实并非如此,因为任何线性符号(linear notation)的优先级要比非线性符号来得高。例如,请试着从左到右阅读下边这行代码:
(“一个指向数组的指针,此数组有10个元素,每一个元素皆为一个函数指针,被指向的函数带有两个整型参数并返回一个bool型值”)如果你既需要声明语法的线性化,又想要C风格的声明语法和表达式语法等价,所有操作符必须是“后缀型”(或者为“前缀型”,但你不能同时拥有这两种语法)。
但是,“业已为人熟知”的力量很强大。让我们以英语为例作为对比。或多或少,我们早就欣然接受了关于“to be”的荒谬的语法规则(am、are、is、been、was、were……),而所有简化它们的企图都被视为“不尊重”或者说得好听点 — 幽默。这真是一个奇怪的世界,过去将来都是如此。
也就是说,编程语言还是远比自然语言来得简单,因此,我希望某天我们可以使用一种更好的声明语法,到那时,我们便会纳闷:“那些老家伙们怎么能忍受同这些荒谬的玩艺朝夕相处呢?”
Elden Nelson:今日世界的处理器速度要比C++刚诞生时的处理器快上数千倍,因此对于很多开发商来说,目前软件开发时间显得比软件运行时间更有价值。C++应该如何改变(若有改变的必要的话)以应对这项根本性的转变?
Bjarne Stroustrup:程序员的时间一直被认为很宝贵,而我们对计算机的时间要求却超出千倍。
鉴于系统性能的不断提高,我认为C++不应该改动,不过,许多程序员却可以从系统性能提高中获益,因为他们可以对低阶效率问题放松一点警惕,而将重点集中到高阶结构和正确性上。这样做意味着更加注重抽象,且要以“一门高阶语言”的眼光来看待C++。由此可受益良多:编程更加容易,移植更加方便,维护更加轻松。甚至还可以获得性能上的好处。现代代码中多数严重的效率问题源于对系统设施和算法的欠妥运用。
每当看到有人使用数组、宏、转型以及指针把C++程序写得一团糟时,我都感到不寒而栗。这种程序看起来就像用C++语法写成的汇编代码。仅仅用标准库的vector和string来代替数组,便是一个巨大进步。
还有,并非所有程序都运行在一台有显示屏、用户等待反馈的这种传统型计算机上。实际上,大多数程序运行于嵌入式系统中以控制我们的电话、汽车、照相机以及气泵。那些情形往往对资源有严格的限制,C++编写紧凑、快速代码的能力尤显重要。另外,许多服务器应用和科学应用是在硬件资源受限的环境下工作的。比方说,假如你使用C++来实现一个气候模型,你必须要有一个如同优化的Fortran一般的库来执行计算。
Elden Nelson:将在2003年出台的标准的下一个修订版中,会有哪些特性加入到C++之中?您认为哪些特性属于当务之急?
Bjarne Stroustrup:委员会已将此话题的讨论延期,直到提交一份关于此内容的缺陷报告,还要发布一份有关性能议题的技术报告,之后才能继续进行。与此同时,鼓励人们积累运用目前标准的实践经验,以及进行有关改进的试验。
我认为这是一种鼓励“稳定性”的良好方式,由此也可以避免削弱委员会可以依赖的时间和技巧方面的有限资源。别忘了委员会是完全由拥有“日常工作”的志愿者组成的。有鉴于此,我可不愿让人看到我想以一些特定的私愿而凌驾于于委员会之上。你可以在这篇采访的其他部分获悉我对此问题的概括观点。
Elden Nelson:刚获批准的C9X标准在ISO C中加入了好几项C++尚未支持的构造。例如long long数据类型和restrict指针,还有其他几项。它们将来会被加入C++吗(果真如此,C++还将需要“restrict引用”,对吧)?您认为编译器厂商们应该等到标准的下一个修订版出台,还是应该以非标准扩展的形式将它们实现?
Bjarne Stroustrup:C99新加的功能会在C++环境中予以考虑。无庸置疑,其中一些特性会被采纳 — 正像C99中也包含了一些C++特性一样。然而,这并不像某些人想象的那么容易。我认为,把C99的全部功能添作C++的扩展同时还要保持与当前C++标准兼容,是不可能做到的。
一个更加严肃而基础的问题是“语言设计哲学”。对C功能的添加是为了提供一些专门功能(非常类似于Fortran对数值计算的支持)。我认为这种方式过时且与C++以及多数其他现代语言所采取的途径相悖,后者更注重语言的抽象机制,这些设施允许用户和库构建者在不增加核心语言复杂性的前提下提供更广范围的专门功能。
C99添加了数据类型(long long和复数)、特别方式的初始化、转换规则以及一个有着特别语法形式的内建数组。这与C++采取的方式形成了鲜明对比。C++通过构造函数指定初始化和转换操作,通过标准库的类提供新数据类型。C采取的方式增加了基础语言的复杂度,加重了内建类型的不规则性,并和C++以标准库方式提供的东西重叠。这就意味着假如你把C99的功能加入到C++,用户就不得不在“C99风格的动态数组”和“C++的vector”以及“C99风格的复数”和“C++的复数”之间做出抉择。
我认为这是C与C++发展过程中的一个协调上的失败,并对C++社群乃至所有为C/C++社群着想的人们造成了严重负担。然而,从网上的消息来判断(这一贯是一种不可靠的行为),有些观点认为难以解决的兼容性问题象征着C语言“独立”的胜利,我却认为C与C++双方委员会亟待更深入的协调,用户社群和C/C++编译器供应商们可以表达出自己的观点以改善现状。
restrict是一个相对简单的问题。restrict可以作为非标准扩展加入到C++而不会造成什么伤害。毕竟,只要利用宏将restrict替代为空就可以将使用它的程序转变成合法的C++程序。你的看法是对的,C++变量还需要提供受限的引用(restricted references)。
restrict为什么不是C++的一部分有下述三个原因:
委员会认为C++已经加入了足够的内容,因此应该将新特性最小化。诸如restrict之类的单独特性在被加入标准C++之前应该先经最需要它的用户社群充分试验。
总体来说,restrict特性并不能总被编译器验证具有安全性,因此委员会认为需要做更多的工作,以确认是否能找到一项表现更佳的替代方案。
C++标准库提供了valarray以支持高性能Fortran-like向量计算。
重新考虑restrict的原因有:
随着更多的处理器要求如“long pipelines”和“parallel execution”之类的架构特性,restrict显得越来越重要。委员会最初讨论restrict时,在C++社群使用所有处理器中,只有大约5%具备使得restrict有价值的高性能特性。时至今日,我怀疑这个比例已接近95%了。
据我所知,我们还没有找到一个可行的方法,使得在C++环境中实现自身静态类型检查。
在C++标准库中,valarray的地位还没到“举足轻重”的地步。果真如此,valarray与restrict共存便不会有问题。因此,更主要的问题在于C同C++ ANSI和ISO委员会之间的协调。无论如何,所有C和C++编译器供应厂商都面临一个两难境地:遵从标准的一个分支乎?使全部功能在所有环境下都可用乎?
我认为厂商可以通过提供大量的编译选项以从这个窘境解脱,这样便把牌打到了用户那儿。最终,用户们会因感到不方便而要求标准化。我希望为C++程序提供反映C++标准的默认编译选项,而为C程序提供反映C标准的默认编译选项。
总之,我鼓励编译器厂商将他们的C++编译器的默认选项设置为“遵从ISO C++标准”。不幸的是,在这方面,Windows世界还有一段路要走。
Elden Nelson:标准C++推出有些日子了,Java也在大踏步地往前赶并取得了显著的进步,您怎么比较Java与C++?您认为Java想要变成像C++一样“好”的语言还需要做些什么?您希望C++从Java身上学到什么经验?有没有什么Java(或其他语言)所具备的特性您认为是可以为C++所吸纳的?
Bjarne Stroustrup:我不比较语言。做好这项工作是十分困难的,而且很少具有专业水准。
我认为C++的进步将会主要以它的用户在使用中遇到的问题以及其自身逻辑为基础。当然,其他语言中的某些思想也会被考虑,但不能被简单的移花接木过来。你必须审视某个功能所支持的技术和概念,并且找到在C++中支持它们的最佳方案。
有时最好的选择是综合使用几种语言。毕竟没有任何一种语言是放之四海而皆优的。C++现在是将来也继续会是在广泛应用领域中最好的语言之一。但是,我们不能被拉下水,不能把所有可能的特性都加到C++里面来向大众献媚。我认为Java和C++现在和将来都会是十分不同的语言,它们语法相似,但背后的对象模型明显不同。
对于我来说,一个很重要的区别是C++有一个ISO标准而Java是一个专有语言。
Elden Nelson:在Java刚刚出现的那几年,有很多欺骗性的言论说它将会是“终极语言”,会取代C++。您觉得在过去两三年里Java对C++开发社群产生了什么影响?
Bjarne Stroustrup:到现在关于Java的不实之辞也还随处可见。暂且不提Java在过去5年间的创纪录的发展,狂热的大众似乎认为Java将最终取代的不仅仅是C++,而且还有所有其他编程语言。但在另一方面,C++的使用仍在继续增长。我不认为Java对于C++的影响已经使得人们转而把本打算用来创造更好的C++工具库的资源调过去开发Java工具库。Java对于学习编程的人来说没有太多的新东西,所以对于C++的定义也没什么影响。在那个领域,Java还得努力追赶。比方说,我认为Sun迟早会往Java里加入类似模板的机制。
人们应该认识到C++和Java的目标是何等的不同。以C++的设计理念来衡量Java或以Java的设计理念来衡量C++,得出的结论都不会太好。
在访谈末尾,或许我该表明态度:C++仍然是我喜爱的语言,还没有哪种语言能够像它那样在如此广泛的应用领域和平台上编写出既高效又优雅的代码 。