KoenigMoo夫妇访谈

作者:Andrew R. Koenig, Barbara Moo
采访:王曦,孟岩
译者:孟岩

【译者注】Andrew KoenigBarbara Moo夫妇是C++领域内国际知名的技术专家、技术作家和教育家。最近,他们的几部著名作品《C++沉思录》(Ruminations on C++),《C陷阱与缺陷》(C Traps and Pitfalls)Accelerated C++中文版即将问世。作为C++ View的成员和《C++沉思录》一书的技术审校,我与C++ View电子杂志的主编王曦一起对Koenig夫妇进行了一次email采访。下面是这次采访的中文译稿。

Koenig的悄悄话】你们问的问题,我们已经答复如下。大部分问题,我们都是分别回答的,有些问题我们两个一起回答,个别情况,只有一个人作答。我们是在尼亚加拉瀑布度假期间完成这次采访的,我脑子里一直在想,对我们的中国读者说些什么好呢?这事想得我头疼。也许结束度假之后,我们能说得更好些。

提问:请向我们介绍你们自己的一些情况好吗?“Koenig”是个德国姓吗?怎么发音呢?“Moo”呢?

KoenigKoenig”是一个很常见的德国姓,在德文里写成“König”,意义是“国王(king)”。不过我的情况很特殊。我祖上是波兰和乌克兰人,不是德国人。这个名字其实是一个长长的波兰姓氏的缩写。我读自己名字的时候,重音放在前面的音节,整体的音韵类似“go”的发音。而一些与我同名的人发音时,第一个音节的音韵类似“way”的发音,我们家里人从来不这么说。

Moo: 谈到我这个姓氏,最重要的一点就是,其发音跟牛叫的声音一摸一样——当我还是孩子的时候,小伙伴们经常模仿牛叫声来取笑我。我父辈从斯堪迪纳维亚移民来美国,这个姓是个挪威姓。我在自己的C++技术生涯中最快乐的时刻之一,就是在遇到Simula阵营里的Kristen Nygaard时,他告诉了我这个姓氏的起源。他说这个姓氏多少反映了我祖先居住的地方——Moo是一个很少见的挪威姓氏,其意义是“荒芜的平原”,既不是亚欧大陆上那种一望无际、水草丰茂的大草原,也不是沙漠。我想不是个很浪漫的姓氏,不过能够跟祖先联系起来,还是很有趣的。

顺便一提,中国读者可能会对以下事实感兴趣。很多人在见到我之前,都以为我是中国人。我甚至收到过来自中国的电话推销,希望我去中国作一次远程旅行,认祖归宗。

提问:Stanley Lippman在《Inside the C++ Object Model》一书中提到了贝尔实验室的Foundation项目,他这么说:“这是一个很令人激动的项目,不仅仅因为我们所作的事情令人激动,而且我们的团队同样令人激动:Bjarne, Andy Koenig, Rob Murray, Martin Carroll, Judy Ward, Steve Buroff, Peter Juhl, 当然还有我自己。除了BjarneAndy之外所有的人都归Barbara Moo管理。她经常说,管理一个软件开发团队,就像放牧一群骄傲的猫。”请问,这段与Bjarne和其他人共事的日子,对你们二位真的那么美好吗?

Koenig那一段日子,在我看来,不过是我长达15年的C++生涯中的一部分,而Foundation项目里的人也只不过是一个更大社群中的一部分。当时我已经开始在标准委员会中开展工作,所以我不仅要与同一屋檐下的人讨论,还要经常与全世界各地的数十位C++程序员互相交流。

Moo: 我倒是更喜欢当年围绕cfront的那段工作经历,cfront是最早的C++编译器,那是一个伟大的团队,而且我们处于一个新语言的创造中心,一种新的、更好的工作方法的创造中心。那是一段令人激动的时光,我将永远保存在记忆里。

提问:作为C++标准委员会的项目编辑,哪件事情最令您激动?我们都知道,是您鼓励Alex Stepanov向标准委员会提交STL,并建议将其并入标准库。关于这个传奇故事,您还能向我们透露一些细节吗?

Koenig那次Barbara和我跑到位于加州保罗阿尔托的斯坦福大学去教授一星期的C++课。当时Alex Stepanov在惠普实验室工作,也在保罗阿尔托,我们以前在AT&T共事过,所以对他之前的工作有所了解。很自然的,我们邀请他共进午餐。席间他非常兴奋的提起他和他的同事正在开发的一个C++库。

不久之后,标准委员会在圣何塞开会,那里距离保罗阿尔托只有不到一小时车程。我觉得Alex的想法实在很有意思,就邀请他给标准委员会的成员讲了一课。我们都觉得,当时标准化的工作已经十分接近完成,他的工作不可能对标准构成什么影响。但是,我们至少应该让委员会成员知道它的存在,起码以后我们可以说STL是被拒了,而不是我们孤陋寡闻,致有遗珠之撼。

那次交流会是我所参加过的技术报告中最令人激动的几个之一。在长长的一天之后,会议接近结束的时候,一半人已经疲惫不堪——可是Alex的精力极其充沛,而且他的思想如此先进,大大超越我们之前见过的任何东西。因此,当会议快结束时,委员们开始认真地讨论,是否应该讲这个库并入C++标准。

当然,后来这个库就被渐渐纳入标准,但其实际过程还是相当惊险的。有好几次至关重要的投票,都可以把它扼杀掉。有一次,程序库子委员会甚至决定投票拒绝考虑Alex的建议,幸好我及时指出,我们通常的议事规程是,先解决旧的议题,然后再考虑新的议题,就算是准备拒绝建议,也不应该违例。我们围绕Alex的建议展开了大量的讨论,最后,终于有足够多的人改变了主意,促使委员会逐渐接受了它。

提问:您二位对于现在的C++教育状况怎么看?我们是否应该更加重视标准库教育,而不是语言细节的教育?或者您有别的看法?

Koenig: 当前C++的教育状况实在太糟糕了。很多所谓的C++教材不过是C语言书,只是在结尾粘贴一点点C++的材料而已。结果呢,他们告诉读者,字符串乃是定长字符数组,应该用标准库中的strcpystrcmp来操作。一个程序员一旦在一开始掌握了这些东西,就会根深蒂固,多年挥之不去。

就其本身而言,C++是一种非常低级的语言。唯有利用库,才能写出高层次的程序来。初学者还不能自己构造库,所以他们要么用现成的标准库,要么自己去写低层次的程序。确实有不少程序应该用低层次技术来构造,但是对于初学者不合适。

Moo: 当然是库优于语言细节。两个原因:首先,学生们可以不必费力包装低层次的语言细节,从而更容易建立整体语言的全局观念,了解到其真实威力。根据我们的经验,学生们首先掌握如何使用程序库之后,就会很容易理解类的概念,学会如何构造类的技术。如果首先去学习语言细节,那么就很难理解类的概念及其功能。这种理解上的缺陷,使他们很难设计和构造自己的类。

不过,更重要的一点是,首先学习程序库,能够使学生培养起良好的习惯,就是复用库代码,而不是凡事自己动手。首先学习语言细节的学生,最后的编程风格往往是C类型的,而不是C++风格:他们不会充分地运用库,而自己的程序带有严重的C主义倾向——指针满天飞,整个程序都是低层次的。结果是,在很多情况下,你为C++的复杂性付出了高昂代价,却没有从中获得任何好处。

提问:在《C++沉思录》中,你们提到:“C++希望面对把实用性放在首位的社群”。不过在实践中,很多程序员都在抱怨,要形成一个好的C++设计实在是太难了,他们觉得Java甚至老式的C语言都比C++更为实用。这种看法有什么错误吗?你们对奉行实用主义的C++程序员有何建议?

Koenig: 你们中国人有没有类似这样的谚语:“糟糕的手艺人常常责怪自己的工具”?还有一句,“当你手里拿着锤子的时候,整个世界都成了钉子”。

编程问题彼此不同。在我看来,就一个问题产生良好的设计方案的途径,就是使用一种允许你进行各种设计的工具。这样一来,你就可以选择最适合该问题的设计方案。如果你选择了这样的工具,那么你就必须负责选择合适的设计方案。

Moo: 关于这个问题,我想用一个项目的实例来说明,那时AT&T最早采用C++开发的项目之一。他们在写一个已经建成的系统的第二版,所以认为对问题域已经有足够深入的了解。他们估计学习C++是整个工作中比较困难的一部分。然而实际上,他们在开发中发现,他们对问题领域并没有很好的理解。于是花费了大量的时间来形成正确的抽象。设计是很困难的,语言问题相对容易得多。我们相信,C++在运行时性能上做了一个很好的折中,能够在“一切都是对象”的语言与“避免任何抽象”的语言之间取得恰到好处的平衡。这就是C++的实用性。

提问:有一点看起来你们与几乎所有的C++技术作家意见不同。其他人都高声宣扬,面向对象编程乃是C++最重要的一面。而你们认为模板才是最重要的。我仔细阅读了《C++沉思录》中有关OOP的章节,发现你们所给出的几个例子和解决方案在某些方面是很相似的。你们是否认为所有“良好”的面向对象解决方案都具有某种共同的特质?是否在很多情况下,OO都不如其他的风格?为什么认为“基于对象”和“基于模板”的抽象机制优先于面向对象抽象机制?

Koenig: 所谓面向对象编程,就是使用继承和动态绑定机制编程。如果你知道有一个很好的程序使用了继承和动态绑定,你能做出怎样的推断?在我们看来,这意味着该程序中有两个或两个以上的类型,至少有一个共同的操作,也至少有一个不同的操作。否则,就不需要继承机制。此外,程序中必然有一个场景,需要在运行时从这些类型中挑选出一个,否则就不需要动态绑定机制。再考虑到,我们所举的例子必须足够短小精悍,能够放在一本书里,还不能让读者烦心,所以对我们来说,很难在所有这些限制条件下想出很多不同的程序范例。

某些面向对象编程语言,如Python,其所有类型都是动态的,那么技术书籍作者就不会面对这样的问题。例如,C++中的容器类大多数用模板写成,因其可以容纳毫无共同之处的对象,所以要求元素类型必须是某个共同基类的派生类毫无道理。然而,在Python中,容器类中本来就可以放置任何对象,所以类似模板那样的类型机制就不必要了。

所以,我认为你所看到的问题,其实是因为很难找到又小又好的面向对象程序来做范例,才会产生的。而且,对于其他语言必须烦劳动态类型才能解决的问题,C++能够使用模板来高效地解决。

Moo: 我同意,我们写的东西让你很容易地得出上述结论。但是在这个特例里,我不认为我们所写的东西代表了我们的全部观点。我们针对C++写了很多的介绍性和提高性的材料。在这本书里,“基于对象设计”中的抽象机制就已经很难掌握了,而又必须在介绍面向对象方法之前讲清楚。所以,我们所写的东西实际上是想展示我们这样的观点:除非你首先掌握了构造良好类的技术,否则急急忙忙去研究继承就是揠苗助长。

另一个因素是,我们希望用例子来推进我们的教学。若要展示良好的面向对象设计,问题可能会变得很复杂。这种例子没法很快掌握,也不适合那本书的风格。

提问:如果说我只能记住你的一句话,那一定是这句:“用类来表示概念”。你在《C++沉思录》这本书里,反复强调这句话,给我留下极其深刻的印象。假设我能再记住一句话,你们觉得应该是什么?

Koenig & Moo: 避免重复。如果你发现自己在程序的两个不同部分里做了相同的事情,试着把这两个部分合并到一个子过程中。如果你发现两个类的行为相近,试着把这两个类的相似部分统一到基类或模板中。

提问:你们在《C++沉思录》中有两句名言:“类设计就是语言设计,语言设计就是类设计。”你们对C++标准库的未来如何看待?人们是应该开发更多的实用组件,比如boost::threadregex++,还是继续激进前行,支持不同的风格,像boost::lambdaboost::mpl所做的那样?

Koenig: 我觉得现在回答这个问题还为时尚早。从根本上讲,C++语言反映了其社群的状况,而当前整个社群里各种声音都有。我看还需要一段时间才能达成共识,确定发展的方向。

提问:有时,编写平台无关的C++程序比较困难,而且开发效率也不能满足需求。您是否认为把C++与其他的语言,尤其类似PythonTCL/TK那样的脚本语言合并使用是个好主意?

Koenig: 是的。我最近在学习Python,得出的看法是,PythonC++构成了完美的一对组合。Python程序比相应的C++程序短小精悍,而C++程序则比Python快得多。因此,我们可以用C++来构造那些对性能要求很高部分,然后用Python把它们粘在一起。Boost中的一个作者Dave Abrahams写了一个很不错的C++库,很好地处理了C++Python的接口问题,我认为这是个好的想法。

提问:你们的著名作品《C 陷阱与缺陷》,《C++沉思录》和《Accelerated C++》中文版即将问世。想对你们的中国读者说些什么?

Koenig & Moo: 我们应该保持谦虚,有很多人已经从我们的书中学到了一些东西。我们很高兴将会有一个很大的群体成为我们读者群的一部分,希望你们从书中有所收获。

提问:我在你们的主页上看到不少漂亮的照片。你们有没有访问中国的计划?那一定可以让你们拍到更多的好照片。

Koenig几乎所有的照片都是用一架中型照相机拍摄的,它又大又重,以至于在1995年,有一次旅行时,我们被禁止把它带上飞机。当然,现在飞机对于行李的控制更加严格了,所以我觉得不太可能带着这台相机去中国旅游。现在我只在车程范围内进行严肃的艺术摄影。

提问:最后一个问题,我们都希望成为更好的C++程序员。请给我们三个你们认为最重要的建议,好吗?

Koenig & Moo:

1.       避免使用指针;

2.       提倡使用程序库;

3.       使用类来表示概念

(完)