Copyright © 1996-2005 Artima Software, Inc. All rights reserved
Contracts and Interoperability
A Conversation with Anders Hejlsberg, Part V
by Bill Venners with Bruce Eckel
November 3, 2003
契约和互操作性
翻译:http://blog.csdn.net/lxwde
摘要
Anders Hejlsberg,C#的主架构师,与Bruce Eckel和Bill Venners 谈论了DLL hell、接口契约、strong anmes以及互操作的重要性。
Anders Hejlsberg,微软的一位杰出工程师,他领导了C#(发音是C Sharp)编程语言的设计团队。Hejlsberg首次跃上软件业界舞台是源于他在80年代早期为MS-DOS和CP/M写的一个Pascal编译器。不久一个叫做Borland的非常年轻的公司雇佣了他并且买下了他的编译器,从那以后这个编译器就作为Turbo Pascal在市场上推广。在Borland,Hejlsberg继续开发Turbo Pacal并且在后来领导一个团队设计Turbo Pascal的替代品:Delphi。1996年,在Borland工作13年以后,Hejlsberg加入了微软,在那里一开始作为Visual J++和windows基础类库(WFC)的架构师。随后,Hejlsberg担任了C#的主要设计者和.NET框架创建过程中的一个主要参与者。现在,Anders Hejlsberg领导C#编程语言的后续开发。
2003年7月30号,Bruce Eckel(《Thinking in C++》以及《Thinking in Java》的作者)和Bill Venners(Artima.com的主编)与Anders Hejlsberg在他位于华盛顿州Redmond的微软办公室进行了一次面谈。这次访谈的内容将分多次发布在Artima.com以及Bruce Eckel将于今年秋天发布的一张音频光碟上。在这次访谈中,Anders Hejlsberg谈论了C#语言和.NET框架设计上的一些取舍。
· 在 第一部分:C#的设计过程中, Hejlsberg谈论了C#设计团队所采用的流程,以及在语言设计中可用性研究(usability studies)和好的品味(good taste)相对而言的优点。
· 在第二部分:Checked Exceptions的问题中, Hejlsberg谈论了已检测异常(checked exceptions)的版本(versionability)问题和规模扩展(scalability)问题。
· 在第三部分: 委托、组件以及表面上的简单性里,Hejlsberg 谈论了委托(delegates)以及C#对于组件的概念给予的头等待遇。
· 在第四部分:版本,虚函数和覆写里,Hejlsberg解释了谈论了为什么C#的方法默认是非虚函数,以及为什么程序员必须显式 指定覆写(override)。
- 在第五部分里,Hejlsberg谈论了DLL hell、接口契约、strong anmes以及互操作的重要性。
DLL Hell以及契约理论
Bill Venners: 在多大程度上可以说“DLL Hell”在实际工作中完全是一个失败的接口约定? 对于某个特定DLL,如果每个人都完全理解并且遵循它的函数约定,那么更新这个DLL,从理论上来说就不会破坏任何代码,对么?
Anders Hejlsberg: 地狱里有很多酷刑。DLL Hell一方面的问题是你并没有遵循自己所承诺的语义上的约定。你做了一些和以前不一样的事情,然后就破坏了代码。实际上,这可能并不是我们所面临的最大问题。DLL Hell的真正问题是,我们并不允许你在一台机器上拥有某个特定DLL的多个版本。一旦你更新了这个DLL,你就更新了所有人的程序,这可是个巨猛无比的大锤子。
Bill Venners: 但是如果大家都遵守约定,难道最近的更新不是应该可以满足这个DLL的所有使用者么?
Anders Hejlsberg: 理论上说,是的。但是任何改动都是潜在的破坏性的改变。即使是修复一个Bug也可能会破坏一些人的代码,比如说这些代码依赖于这个bug。按照最严格的定义,你会发现一旦软件发布以后你就不能再做任何改动了。
引入版本(Versioning)是为了在正确的方向上放宽这些规则,并且有回旋的余地。勿庸置疑,能够保证不破坏任何东西的唯一方法就是什么都不改变。因此,针对同一功能的不同版本,在同一个box里甚至是同一进程内,支持并行的(side-by-side execution)执行是非常重要的。并行执行(side-by-side execution)是我们在.NET里支持的一个选项,而在老的DLL模型里我们是不支持这一点的。
Strong Names in .NET
Bill Venners: 我猜想你使用strong names是为了鉴别所需要的库的版本。Strong names是如何工作的?
Anders Hejlsberg: Strong names有一个逻辑部分和一个物理部分。逻辑部分由名字空间和类名称组成。实际上,在公共语言运行时库(CLR)看来,名字空间并不真正存在。我们可以假装名字空间存在于编程语言里,但是在CLR看来,一个类名是可以含有点号的。这就是类的逻辑名称。物理名称包括类代码所在的assembly的名称、版本号、locale、以及与之相关联的密钥。
你可以通过特定的版本号或者特定的strong key来指代特定assembly的特定类型。你可以完全保证要么准确地拿到你所编译的实现版本,要么什么也拿不到。或者,你可以放宽一部分strong name。你可以说,“我要比这个版本新的任何版本。”
强制性的语义约定
Bruce Eckel: 关于通过某些方法做强制性的语义约定,你是否有过一些有意思的想法?
Anders Hejlsberg: 我认为最有希望会成功的点子已经存在了,关于前置条件和后置条件、断言、不变量等等也有新的进展。微软研究院有几个正在进行的项目,我们经常会对这些项目进行评估。我们也看过一些非常具体的建议。最后我们意识到——这一点几乎对于任何真正重要的特性来说都是如此——你不可能仅仅从一门编程语言的角度来做强制性的契约编程。你必须把它弄进基础设施、CLR以及公共语言规范(Common Language Specification),这么一来,也就是说所有其它语言都要支持。如果对于某个接口的实现者来说,是否需要包含不变量的代码是可选的,那么把这个不变量放入接口还有什么意义呢?所以说,这个问题实际上更应该是类型系统级别,而不是编程语言级别的,但是这并不意味着我们就不打算考虑这个问题。下一个发布版本不会处理这个问题,但是它会是C#以后版本的一个头等重要的特性。
互操作性
Bill Venners: 你曾经说过,Java试图做到的是平台独立,而.NET所追求的却是互操作性。说到互操作性,你是指什么?
Anders Hejlsberg: 互操作性有好几个方面。首先,它指.NET里不同编程语言之间的互操作性。我们的设计目标是,.NET CLR应该是语言中立的,这样它就能支持多种编程语言。与此不同,Java仅仅是一门编程语言和针对这门编程语言的执行机器。CLR支持许多只在某些编程语言里才有的特性,比如指针。C#和managed C++的不安全代码支持指针,而Visual Basic和Jscript不支持。但所有关于指针的基础设施都在CLR里面。语言的互操作性基于我们在做了许多尝试之后认识到,我们不应该试图说服每一个人只使用一种编程语言来编程。老实说,业界之所以向前发展并且有所创新,要得益于新创造的这些编程语言。我们不但不会试图阻止这件事情,而且还会给予它更多的鼓励。
互操作性的另外一个方面是指与现有系统的互操作。我们以前摆弄Java的时候,对于我们的Java虚拟机我们试图提高的一件事情就是与已有代码的互操作性,因为我们觉得这种互操作性太重要了。现在我们还是这么认为的。因此,在CLR里,我们把与DLLs、COM、OLE自动化的互操作性看得极为重要,因为在.NET以前所有的代码都是基于这些技术写的。
这就又回到了我前面[In Part IV]所说的,现今最重要的是利用已有的东西。我们必须为程序员找到利用现有系统和代码的方法。要达到这个目标就意味着需要很强的互操作性,因为除此之外你还能怎样做到利用现有系统呢?这使得我们完全站到了Java观点的对立面,Java认为这个世界是“100%纯的”。而我认为我们所做的是正确的事情。我确实是这么想的。
如果你把从C#里调用DLL的感觉和从Java调用做一个比较,很快你就会明白我的意思。JNI用起来很复杂,我觉得很遗憾,他们没把这件事情做得更好,因为确实还有很多东西可以做。当你需要与其它系统进行互操作的时候,如果你处在一个更低级的世界,并且很可能比直接使用C或C++编程更为复杂,那就没有什么意义了。你必须得跑一大堆工具,产生一些头文件。还得记得调用这个调用那个。如果你想要给一个对象去引用(dereference),最好记着先给它加锁,否则程序运行的时候可能会有千分之一的情况,当垃圾收集器碰巧清除它的时候,它就被移动了。然后你就再也不能重新产生了。如果某个系统可以做垃圾收集和类型安全,以及更多的事情,为什么它不能帮你做互操作呢?看起来这是一件再合理不过的事情了。
Bill Venners: 以我的视角,从外部来看微软和Sun,我注意到两个公司有一种文化上或者说哲学上的不同,我想这种不同影响到了Java和.NET的设计。在微软,我感觉有种占主导地位的观点,就是写软件是用来给硬件(盒子,设备等等)编程的。我想,考虑到微软是如何赚钱的,这就是一种完全合理的观点。与此不同,尽管“网络就是计算机”是Sun的一个市场宣传口号,但是我发现这种态度在很大程度上确实存在于Sun的文化里面。网络(而不是盒子)提供服务,而Java就像是一个位于网络栈之上的面向对象层,它的目标是通过抽象去除连接到网络上的异构性。
Anders Hejlsberg: 有意思的是,现实世界中稍微有点来头的任何Java方案都有与特定平台相关的东西在里头。我没有听说过任何东西是不依赖于其它组件的纯的Java。Web上所有东西都依赖于Apache或者其它的Web服务器、数据库,以及与这些系统的某种形式的互操作。认为整个世界是纯Java是很搞笑的。整个世界是指把许多系统放到一起并且让它们跑起来。这也就是为什么web services让大家如此激动,因为它们有很棒的方法来进行互操作。我们认为互操作性有许多种形式,而我们应该尽我们所能使得系统之间可以更好和更容易地进行互操作。
Bill Venners: 实际上,你刚才所描述的情况正是我的Artima.com服务器所使用的东西。我用Tomcat跑JSPs,而Tomcat与Apache进行交互。
Anders Hejlsberg: 你大概还有个数据库。
Bill Venners: 是的,我的Java程序也与数据库进行交互。因为Java API的实现用到了JNI,从这种意义上说它确实有平台相关的东西在里面,但是我的程序代码都是Java。而且即使是Tomcat与Apache和数据库的连接器也都是纯Java的,因为它们使用sockets而不是JNI来进行互操作。
Bruce Eckel: Python有一点让我非常喜欢,如果你想要平台无关那就平台无关,如果你想与平台打交道的话,也可以。
Anders Hejlsberg: 是的,确实如此。是否平台无关应该由你来选择。
下周
Anders Hejlsberg访谈的下一部分将会在不久以后贴出来。如果你想收到Artima.com上新文章每周简报的电子邮件,请订阅Artima Newsletter。
反馈
对本文所描述的设计原则有自己的观点么?那么请到News&Ideas论坛讨论这篇文章,Contracts and Interoperability.
资源
深入C#:微软主架构师Anders Hejlsberg访谈:
http://windows.oreilly.com/news/hejlsberg_0800.html
A Comparative Overview of C#:
http://genamics.com/developer/csharp_comparative.htm
Microsoft Visual C#:
http://msdn.microsoft.com/vcsharp/
Anders Hejlsberg不是Artima的采访对象中第一个提到品味的。Jim Waldo在他的访谈中针对构建一个由有品味的程序员组成的团队给出了几乎同样的评述:
http://www.artima.com/intv/waldo10.html
Ken Arnold’s的访谈有一整部分都是关于设计品味的——品味和美学(Taste and Aesthetics):
http://www.artima.com/intv/taste.html