现在的位置: 首页 > 综合 > 正文

Bjarne新文章《Evolving a language in and for the real world: C++ 1991-2006》的读后感

2013年10月24日 ⁄ 综合 ⁄ 共 7805字 ⁄ 字号 评论关闭

Evolving a language in and for the real world: C++ 1991-2006》是Bjarne Stroustrup20076月,在HOPL-III上发表的一篇新论文。

文章大体的内容同D&E相近,但补充了一些新的信息,特别是D&E出版后C++的发展和变化,以及对未来的展望。更重要的是,Bjarne一反D&E里中立的态度,比较了几种热门语言同C++的差别,非常有趣。

该文的原版链接在这里(http://www.research.att.com/~bs/hopl-almost-final.pdf)。但水木的overcomeunic不辞辛劳,翻译了这篇整整60页(够得上单行本了)的巨大paper,这里对其表示敬意和万分的感谢。文章中文版的连接在此处。也可以从ponba的讨论组TopLanguage下载

我花了大半天的时间,几乎一口气看完了这篇文章,感想颇多。于是决定写下来,同大家一起交流。

 

开篇是一些概括性的介绍。然后便是早期历史,这些也没什么,D&E上基本都有。引起我注意的,是第8页关于iso标准进程的内容。D&E中讲述过一些,但这里提供了更多的细节信息。有这样一段话引起了我的注意:

J16委员会的成员是自愿者,他们必须付钱(一年大约800美元)去获得做这些工作的荣幸。因此,大部分的成员代表公司,公司愿意支付会费和旅行开销,但总有一小部分人得为自己买单。

我把这段paste给一个同事看。他立刻回复我:“倒贴啊!”。不过几秒钟后,他马上发出了感叹:“他们的学术环境很好,中国现在是利字当头,不会有人去做这种事情的。”当然,对于那些公司支付费用的而言,并没什么。令我们感到诧异的是那“一小部分得为自己买单”的人。从文章后面的内容来看,这种苦差事,别说“倒贴”,就是付钱少了,也很少有人原意干的。

 

这段紧接着讲述WG21(ISO)的情况。然后是投票的方式等等。这段最后以这样一句话结束:

对于1997/1998的最后标准投票,ANSI投票是43-0ISO22-0。我们真的达到了一致性,甚至是全体通过。我被告知这样明确的投票是很不寻常的。

这种一致性当然是委员会成员长期努力的结果。这也是这个组织充分平衡的结果。当然,后面可以看到,这种平衡通常也会造成很大的问题,甚至是伤害。

 

对于大多数成员来说,与C++的早期版本(ARM C++[35])兼容,与C的早期版本(K&R C[76])兼容和公司的各种方言兼容是一个严重的事件。我们(委员会的成员们)尝试面对将来的挑战,比如并发,但我们真的牢记C++是许多工具链的基础。破坏C++,那么JavaC#的主要编译器也会被破坏。显然地,委员会不能通过不兼容性来“破坏C++”,尽管不兼容性会破坏C++。工业界会简单地忽视一个严重的带有不兼容的标准,同时开始偏离C++

这段内容明显地表明标准化的重要性,同时也表明C++有多么大的历史负担。

 

3.3 ISO C++标准进程,第10页,:

1991年的Lund(瑞典)会议后,下面的警戒性的传说在C++社团中流行起来:

我们常常提醒自己关于轮船Vasa的故事,那时它是瑞典海军的骄傲,计划建造成有史以来最大和最漂亮的战舰。不幸的是,为了装载足够的雕像和大炮,它在建造过程中经历了重大的重新设计和扩展。结果是它在跨Stockholm港湾的途中,一阵风过后它就沉了,大约

50人遇难。这艘船已经被打捞上来,你可以从Stockholm的博物馆里看到它。它看起来非常漂亮—比它第一次扩展重新设计前漂亮得多。也比那些17世纪的战舰漂亮得多—但那不能成为它的设计者、建造者和预期的使用者的安慰。

这个故事经常被提起,作为反对增加特征的预警(那就是我告诉委员会的场景)。不管怎么样,对于复杂的事物,总有另一面:如果Vasa已经完成原来的设计,当首次遇到“现代的两层甲板”的战舰,它也同样会被打得满身是洞,沉到海底。忽视世界中的改变也不是选择。

关于Vasa战舰的故事D&E里已经说过了。最后这一段则是新的内容。这表明了任何事物都必须不断变化。而反过来,为了避免Vasa的结局,应当事先考虑周密,需要更富于远见。

 

4.1 STL 11

讲述了STL的故事。从STL前的传统做法开始,到STL的创建过程和思想。其中提到了Bjarne对容器的要求:

STL代码看起来非常不同,然而,多年后我总结出一个清单,那些我认为对于容器来说是很重要的属性都列于其上:

1、单独的容器是简单和高效的

2、容器提供它的“自然的”操作(比如,list提供putgetvector提供下标操作)

3、简单操作,比如成员访问操作,不需要函数调用用于它们的实现

4、提供公共函数(可以通过迭代器或基类)

5、容器默认是静态类型安全的,并且是homogeneous(即在同一个容器的所有元素的类型相同)

6heterogeneous容器能够由存储指向共同基类的指针的homogeneous容器所实现

7、容器是非侵入式的(比如,要成为容器的成员,一个对象不需要有特殊的基类或链接的字段)

8、容器能够包含内建类型的元素

9、容器能够包含有外部强加布局的structs

10、容器能应用在一般的框架上(容器和在容器上的操作)

11、没有sort成员函数的容器也能排序

12、“公共服务”(比如persistence)能独立地提供给一组容器(通过基类?)

这些标准多少有些理想化,但STL都做到了(除了最后一条)。足见Stepanov的智慧。

 

它花了我一些时间—很多周—去习惯STL

学习STL需要很大的转变,即便Bjarne,也花了这么多时间。其中Koenig起了至关重要的作用。KoenigC++上所起的作用,可以说仅次于Bjarne,但他的名气远不及Bjarne,甚至Meyes。这位幕后英雄的这种执着,令人敬佩。

 

4.1.3 STL理想和概念,p10

那么STL是什么?它来源于一种尝试,应用数学的一般性的理想去解决数据和算法的问题。对容器里面的对象进行排序并写一个算法去操作这些对象,对这类问题的思考也就是理想的方向,独立和组合地表达概念:

  用代码直接表达概念

  用代码直接表达概念之间的关系

  用独立的代码直接表达独立的概念

组合代码自由表达概念,只要组合言之有理。

这让我想起了工业界已经使用了百余年的模块化和组件化方式。在过去,很多人都试图让编程也具备这种能力。但STL所展示的技术,则是第一次如此灵活、自由、简洁和优雅地实现了这种方式。STL的出现彻头彻尾地改变了C++的编程,使得C++成为了一种全新的语言。可惜的是,业界似乎尚未从OOP的震撼中清醒过来,对于这种技术的价值,还未有深刻的认识。(这就像神经细胞,一次发放之后,总会有个“不应期”,不对任何刺激做出反应)。

 

5.2 export论战,p31

关于Export的论战。讲述了这样一个故事:

这个伤感传奇的真正主角是EDG编译器的实现者:Steve AdamczykJohn SpicerDavid Vandevoorde。他们强烈反对分离模板编译,最后为达到最佳妥协投赞成票,然后花了超过一年的时候完成了他们所反对的东西。这就是专业!编译器的实现正如他的竞争对手所预测的那样困难。但它成功了并带来了一些好处,正如它的支持者所承诺的那样。不幸的是,由于一些对分离模板编译的必要的约束,因此承诺以因没能提供它们预期的利益并且让编译器变得更加复杂而告终。一如往常,在技术问题上的政客般的承诺导致了“warts”。

职业的精神,这种人才称得上大师。

 

5.4 自动废料收集,p34

出乎我的意料,BjarneC++GC倡导者,甚至还发出了一个提案。我一直以为Bjarne反对gcC++0x最终还是会引入gc,而且更加完善。或许当时没有加入gc是对的。反观java等语言的gc,显得那么不成熟。现在新的gc模型要进步许多,或许现在才是C++使用gc的时候。

 

5.5 未完成的工作,p36

对“为什么我们没有提供更多有用的库”的回答是简单的:我们没有资源(时间和人力)去做比我们所能做到的更多的工作。

唉,都是钱闹得。

 

1992年,TI提供他们的非常漂亮的库用于考虑,在一个小时内,有5个主要公司的代表清楚地表达了他们的观点:如果这个库被认真考虑的话,那么他们将推荐他们自己公司的基础库。这不是委员会所能接受的。对一致性要求不是很高的委员会也许会通过从商用库中选择一个来达到目的,但对于C++委员会来说,这是不可能的。

商业利益总是象一剂毒药,损害着真正重要的东西。

 

1994年同样也是必须被记住的,许多人已经认为C++标准库太大了。Java还没有改变程序员的观点,即他们可以从一门语言中免费得到某些东西。反而,C++社团中的许多人使用微小的C标准库作为库大小的比较单位。一些国家代表(荷兰和法国)反复表达他们对C++标准库的膨胀的担忧。象委员会中的大多数人一样,我也希望标准会对C++工业库有所帮助而不是取代它们。

这些都是平衡带来的问题。

 

6.1 性能技术报告,p38

与其空谈C++的性能如何如何,或者没完没了地争论C++C谁快,还不如认认真真地去看看这些报告,来提升自己的水平。谁都可以得益,不管用不用C++

 

6.2 TR库,p41

尽管标准库和它的扩展的重要性是非常巨大的,我在这里只能简要地列出新的库:

  多态函数对象封装器

  Tuple类型

  数学的特殊函数

  类型粹取

  正规表达式

  增强的成员指针适配器

  通用的智能指针

  引用封装器

  用于计算函数对象返回类型 的统一的方法

  增强的binder

  hash table

这些库也都是些基础库,尽管非常关键,有用。但程序员的需求远远超过这些。况且除了boost,还没有哪家厂商正式实现它们。我们只能等待C++0x早日到来。

 

7.1 应用编程vs系统编程,p43

尽管Bjarne一再声称C++主要领域在系统编程方面,但实际上,就目前的C++能力而言,同样也非常适合应用编程,尽管不是最适合的。在C++的整个发展过程中,人们发现C++具备了所有领域开发的能力(且不论是否最适合),或者说具备了很好的基础。于是,大家都希望把有利于自己的技术安插进去。C++最终成为了一种几乎是“全能”的语言。这是好事,也是坏事。语言的复杂度使得人们望而生畏(多半是心理因素,和环境影响),而教学和培训的压力陡增,这使C++在现在这种只注重“表面效率”的环境下,生存会变得更加艰辛。但强大毕竟是强大,当我们充分思考了“如何更好地完成软件”这个问题后,会发现,C++在很多方面,特别是服务性组件开发方面拥有很大的优势。所以,我认为,C++的定位应当是“基础编程”,而并非仅仅是“系统编程”而已。

 

7.4 ABI和环境,p47

我们经常说C++的这缺陷,那不足。实际上,在我看来,从长远角度来看,C++最主要的问题是ABI,也就是缺少一个统一的二进制移植标准。从发展趋势看,未来不可能有一种语言在大多数领域占统治地位。语言间的合作、取长补短,是一种非常好的策略。但这需要语言间拥有统一的接口标准。目前的C++,即便是其自身,也没有统一的二进制接口,何以因应未来的发展呢?

 

7.7 JavaSunp50

这是最精彩和最有趣的部分。人人都想知道Bjarne如何评价Java。这回他总算破例,让我们开开眼。

然而,已经有许多关于C++/Java关系的说法,Java在市场中的存在已经影响到了C++社团。因此,一些评论不可避免,尽管恰当的语言比较不在本文的考虑范围之内,甚至在C++的定义中也没有Java的踪影。

这段话的意思差不多就是:你Java已经挖坏了我家墙角了,我也得动点真格的了。

 

为什么不?从Java早期,C++委员会总是包含那些有许多Java经验的人:使用者、实现者、工具构建者、和JVM实现者。

就是说:没我C++,哪来的你Java,别忘本!

 

我认为在基础层面上,JavaC++是在传达想法时有很多不一样的东西。特别地:

  C++依赖于直接访问硬件资源,去获取它的许多目标,然而Java依赖于虚拟机,从而让它远离硬件

  C++只带有限的运行时刻的支持,而Java依赖于许多元数据

  C++强调与用其它语言写的代码的互动,并且共享同一系统工具(比如链接器),而Java的目标是通过将Java代码与其它代码隔离,从而达到简化的目标。

咱根本不是一个档次的东西,有什么好比的。

 

9.2.2,我概述出用于C++的基本设计准则:一个比C++更好的语言将意味着什么?考虑第一位的决定:

  使用静态类型检查和Simula类似的类

  分离语言与环境间的关系

  C源代码兼容性(“尽可能地近”)

  C链接和布局兼容(“真正局部变量”)

  不依赖于废料收集

请注意,最后一条。只是说“不依赖于”gc,就是说没gc也得能活,有当然更好了。

 

C++并不满足Java的设计准则;它也不想满足。类似的,Java也不满足C++的设计准则。

咱不跟你一般见识。

 

不幸的是,Java支持者和他们的市场机器不是宣扬Java的本质,而是对Java与其它语言(大多指CC++)做了许多不公的比较。正如2001年晚期,我听到Bill Joy声称(可能是在技术介绍时口头上说的)说“可靠的代码不能用C/C++写,因为它们没有异常”(参见§5,§5.3)。我认为JavaSun用于对付微软的商业武器,但却误伤了旁观者:C++社团。它同样伤害了许多更小的语言社团;比如SmalltalkLispEiffel等。

这才说到了正题上了:你Java不能欺人太甚。你可以玩你的商业花招,但不要伤及无辜。Java早期的宣传的确是针对ms的,后来为什么会来“踢C++的场子”,就搞不清了。

 

尽管有许多Java不会取代C++的承诺(“Java会在两年内完全干掉C++”是1996我参加一个图形发布会时反复听到的)。事实上,C++社团在Java第一次出现之时到已经翻了三倍。Java没有真的干掉C++,然而,通过转移需要用于工具、库和技术工作的精力和资金,伤害了C++社团。另一个问题是Java鼓励一个狭隘的“纯面向对象”的编程观点,过分强调运行时的解析和轻视静态类型系统(只有在2005Java引进了“generics”)。这导致许多C++程序员模仿写了许多不优雅、不安全和效率低下的代码。当这种狭隘的观点影响到教育,并在学生中引起对不熟悉的事物的恐惧时,这个问题就变得特别严重。

说实在的,这才是真正令人担忧的。无论是Java还是C#,总是为了商业利益,误导着业界的技术发展。这种技术上的伤害,通常需要很多年才能逐渐恢复。就像被人类过度污染的地球,即便在人类消失后,也要过成千上万年才能恢复原样。而此间,无论是企业,还是个人,都会付出更大的代价。

 

正如当我第一次听到有关Java的简单和性能的吹嘘时所预测的那样[136]Java迅速添加新特征—有些是与C++一样的。新的语言总自称是“简单”并对现实世界的应用程序是有用的,然后它们在大小和复杂度上不断增加。不管是Java还是C++都不能摆脱这些效应。显然,Java已经在效率上取得了很大的进步—考虑到它的最开始的缓慢,它当然会取得很大的进步—但当抽象被严重使用时,Java的对象模型抑制了它的性能(§4.1.1,§4.1.4)。

抛开Bjarne自吹自擂的预测不谈,其他的都是实话。一个试图完成应用开发的语言,总会不断地遇到扩张的需求,以满足实际开发中的要求。就像苏联(俄国)人开发的武器,尽管一直宣称要简单、实用(实际上是他们在复杂系统,特别是电子系统方面太落后)。但随着战场特征的改变,也不得不把成吨的电子设备搬上坦克和飞机。这是自然规律。

 

我的猜测是Java能与C++进行比较的真正力量在于它的二进制兼容, Sun事实上已经通过对Java虚拟机的定义,控制了链接器。这给了Java链接兼容性,那是C++社团所没有的,因为使用基本的系统链接器和C++提供者没有在关键平台上达成一致的协议(§7.4)。

毕竟是搞学问的人,还是肯承认一些不足的。如果能够多谈些易用性、易学性方面的比较就更好了。

 

7.8 微软和.Netp51

对于msBjarne似乎比较客气,但也表达了对C++/CLI的一些不满。而且对其没有通过ISO标准,似乎有些幸灾乐祸。

 

8章开始了整片文章的重头戏(大轴):C++0x。这也是最值得期待和最令人兴奋的部分。

8.1 技术挑战

C++0x开始构思时,C++社团所面对的技术挑战是什么?从高层次上,这个问题可以这么回答:

  基于GUI的应用程序构建

  分而式计算(特别是web

  安全

这个早期清单和最终的C++0x特性清单是有很大差别的。

 

从许多讨论和陈述中,我已经有了一个简短的用于C++0x的一般目标和设计规则的总结,看起来能被广泛接受,目标是:

  C++成为系统编程和库构建的更好的语言—而不是提供特别的设施用于支持特定的子社团(比如,数值计算和视窗风格的应用程序开发)

  C++更容易教与学—通过增加统一性,更强的保证和设施支持新手(新手永远比专家多)

经验法则:

  提供稳定性和兼容性

  优先使用库,然后才是语言扩展

  只做那些会改变人们思考方式的改变

  一般性优先,然后才是特化

  同时支持专家和初学者

  增加类型安全

  改进性能和直接在硬件上工作的能力

  适应现实世界。

这些目标多少有些理想化,但是C++确实在向这方面努力。特别是“同时支持专家和初学者”,难度的确很高。但是从后面的讲述来看,似乎还有些苗头。

 

这些条款中的大多数是在前面列出的“经验法则”的指导下工作的。那个列表比委员会收到的建议(以一种强迫(至少简要地)去考虑它们的形式)的一半还少。我从email和与用户会议搜集到的建议是它的好几倍。

人们都希望C++按照自己的需要成长,把C++委员会当成许愿的喷泉了。但这从另一方面也反映出开发人员对一种完善的语言的渴望(不管是否现实和合理)。

 

8.4 阻碍,p61

我的其它优先权(与更好地支持泛型编程一起)是更好地支持初学者。提议的显著的趋势是偏向老练的使用者,他们提议并评估这些提议。帮助新学者在几个月内变成老手的简单的东西通常被忽视。

Bjarne不止一次地表达过这个愿望,但似乎委员会更执着于“高技术”。但不管怎么样,至少让我们看到有人正在为此努力。

 

我希望许多起小的“障碍”不会在C++0x中出现。然而,我,Francis Glassborow还有其它的人,尝试系统地消除许多频繁出现的“障碍”,看起来没有结果。

考虑到C++的历史包袱,以及委员会的社会责任感,(这里先鄙视一下ms,它会随意改变产品的特性,以破坏既有的代码),这种尝试将会是非常困难的。我衷心地预祝,并热切地期望他们能够成功。

 

“障碍”的另一个例子是使用默认拷贝操作(构造函数或赋值)去拷贝一个带有用户定义的析构函数的类的对象是合法的。需要用户定义的拷贝操作将会消灭许多跟资源管理有关的肮脏的错误。

C++还有很多这类缺陷,比如,具有继承关系的类的数组间的转换;非虚析构函数基类上的多态等等。这些问题如果能在语言层面加以制止,C++

抱歉!评论已关闭.