原文
译者注:
提到 Anders Hejlsberg,Delphi 与 C# 两大阵营都会肃然起敬------一个人,塑造了两种截然不同的语言体系。但 Anders 的传奇远不止于此。
上世纪七十年代末,他还是哥本哈根大学的一名学生,在 PC 尚未普及的年代,便为 Z80 套件机编写编译器。那个不起眼的小项目被 Borland 收购后,蜕变为 Turbo Pascal ,一款定义了整整一代程序员编码体验的上古神器。十三年间,他主导了八次重大迭代,又亲手缔造了 Delphi,将可视化开发与面向对象编程完美融合,让"拖放控件、双击写代码"成为 Windows 开发的黄金标准。
正当 Borland 如日中天,他却转身加入微软。没有留恋股权与荣光,只因"想尝试一些不同的东西"。他先是设计出 Visual J++ 的 WFC 类库 ------这套当时看似过渡性的技术,实则是日后 .NET WinForms 的直接祖先。随后,他悄然开启了一个更宏大的秘密项目:一种汲取 C++ 之力与 Java 之雅,却将组件编程提升为一等构造的新语言------C# ;以及与它并行诞生的 .NET Framework,一个旨在终结"语言孤岛"、让二十余种编程语言共享同一运行时的统一平台。
从 Z80 汇编到 Turbo Pascal,从 Delphi 的可视化革命到 C# 与 .NET 的统一蓝图------Anders 的每一次转身,都精准踩在计算范式变迁的节点上。
2001 年夏,TechEd 欧洲大会,Anders 罕见地接受了专访。
彼时, .NET 尚未正式发布,C# 仍带着神秘面纱。在这场对话中,他首次系统阐述了 C# 的设计哲学、.NET 的多语言愿景,以及那些贯穿其职业生涯的技术传承。
以下是这次专访的完整记录。

TechEd 2001 的主题演讲由编程先驱 Anders Hejlsberg 主讲。除了是微软 C# 的首席设计师,他的履历还包括创建了 Borland Turbo Pascal 和 Delphi。在这篇与 Matt Nicholson 的独家专访中,他深入介绍了加入微软以来的工作,讨论了 C# 和 .NET。
原载于 DNJ Online,2001年7月
Matt:你在微软做了哪些工作?加入公司之前你的经历是怎样的?
Anders: 我实际上是丹麦公民,在哥本哈根出生长大。大约13或14年前我搬到了美国。我从1979年就进入了这个行业。我在丹麦技术大学读书期间,和一些人一起创办了一家小型计算机公司。我想我们是哥本哈根第一家计算机店,那是在PC出现之前的萌芽时期。我们是英国套件计算机 Nascom 的分销商。它基于 Z80 处理器,我编写了大量不同的软件,比如汇编器和反汇编器------你知道那时候会写的那种东西。我还写了一个小型 Pascal 编译器。你可以把微软的 ROM Basic 拔出来,插上我们的小 Pascal 编译器。从某种意义上说,它是 Turbo Pascal 非常早期的前身。它带有屏幕编辑器,可以在内存中编译,然后执行机器码。它在 CP/M 上发展成了一个更完整的实现,然后我的公司与 Borland 的创始人建立了联系,将这项技术授权给了他们。这基本上就成了 Turbo Pascal。他们对我们编写的软件进行了重新品牌包装。
Matt: 你的公司叫什么名字?
Anders: 叫 PolyData。最终它的发展超出了任何人的想象,我最后完全为 Borland 做软件开发。最终我将我们的版税合同换成了 Borland 本身的股权,并搬到了美国。我在 Borland 待了13年,从1983年成立到1996年。我们发布了大概七八个版本的 Turbo Pascal,以及三个版本的 Delphi------这是 Turbo Pascal 的继任者。我是该产品的首席架构师。然后我于1996年加入了微软。在13年之后,我需要尝试一些不同的东西!
Matt: 是为了做 .NET 吗?
Anders: 实际上是在 .NET 之前。我们直到1997年底或1998年初才开始做 .NET。我刚到微软时,担任的是 Visual J++ 6.0 的架构师。微软之前发布了 1.1 版本,基本上就是把一个 Java 编译器塞进 Visual Studio IDE。除了编译器之外,没有什么真正是 Java 特有的;项目模型仍然是 C++ 的项目模型,不太合适。所以我们构建了后来成为 Visual J++ 6.0 的产品,还有 Windows Foundation Classes(WFC)------我们 Windows 专属的类库。
Matt: 你在 WFC 中的参与程度如何?
Anders: 我是 WFC 的架构师。
Matt: 有些人认为 WFC 是 .NET 中许多理念的先行者。
Anders: 它确实是如今 .NET Framework 中被称为 WinForms(或 Windows Forms)的先行版本。所以 .NET 框架中的客户端 UI 程序包与 WFC 有着直接的传承关系。任何了解 WFC 的人都会立刻对 WinForms 感到熟悉。
Matt: 那么 Jump to .NET 工具包对 J++ 开发者来说也会很熟悉吗?
Anders:当然,而且它的目标群体显然有两类:使用 Sun 类库进行 Java 开发的人,以及使用 J++ 和 WFC 类库进行开发的人。从 WFC 到 Windows Forms 的过渡几乎是机械式的。我们使用了不同的约定,现在我们有一种真正支持属性和事件的语言,因此某些东西的语法有所不同。它演进到了下一个逻辑步骤,但它是 WFC 的直接后裔,所以代码中没有什么真正结构性的东西需要改变。当然,任何使用 Sun 类库编写的代码涉及的是一种非常不同的开发理念,因此转换步骤要复杂一些。
Matt: .NET 的其他灵感来源或构建模块是什么?
Anders: 我想说,我们大量的 VB 代码,当然还有 Java 本身都充当了灵感来源。很多客户在使用 Java 并告诉我们他们喜欢使用它。我们非常尊重那个平台,毫无疑问。
还有许多其他东西充当了灵感,鉴于我的背景。Delphi 当然一直是灵感来源------你也可以在 Windows Foundation Classes 中看到这一点。很难忘记那些你认为正确的东西。我认为这在软件开发中很常见。Java 确实深受 Smalltalk 和其他类似面向对象系统的影响。
Matt: 你在 C# 中的参与程度如何?你是什么时候开始着手它的?
Anders: 我是 C# 语言的首席设计师,我们在两年多前开始工作------也就是1998年底。我们更早就开始了如今 .NET Framework 中 Common Language Runtime(CLR)的工作,所以我们是并行开发语言、编译器和运行时的。
Matt: 设计 C# 的理由是什么?为什么你觉得有必要开发一种新语言?
Anders: 我认为有很多原因。首先也是最重要的是,我们想要一个能够面向 C++ 开发者的产品,将他们带到生产力和易用性的下一个层次。你可以说,我们真正追求的是 C++ 的强大和表现力,但拥有像 Visual Basic 和 Delphi 这类语言的易用性。
然后我想还有一些其他宏大的理念。其中一个关键观察是,编程语言经历了从我所称的结构化编程(如 C 和 Pascal)到过程导向语言的演变,后者有适当的方式来构建数据抽象,通过结构体和记录等。这演变成了面向对象编程,始于像 Simula 这样的语言,并逐渐通过 C++ 和 Object Pascal 被主流采用。我们尝试从 C++ 到 C# 所做的,首先是我之前谈到的简化和提高生产力,同时也是构建一种支持我所说的"组件导向编程"的语言。
随着时间的推移,一整套编程模型已经演化成我们所说的 PME 模型------构建组件的属性、方法、事件模型。你还可以把集成文档和定义组件如何嵌入宿主环境的属性等也纳入其中。你想要一种语言,在其中构建组件是完全自然的,构建组件的所有方面都是编程语言中的一等公民。
如果你看看 C、C++ 和 Java,或者那些属于 OOP 但不一定属于组件导向的语言,你会发现属性、方法和事件实际上几乎被普遍用作一种范式。ActiveX 控件、JavaBeans、Delphi,或者无论什么------每个人都使用那种范式来构建组件。
但这些编程语言并没有真正将所有这些核心概念作为一等语言元素。例如,在 Java 中,你当然有方法,但属性和事件并不真正存在;它们是通过命名约定来模拟的。我们都默认同意属性是两个方法,一个叫 'Set xxx',另一个叫 'Get xxx'。确实,当你在属性检查器中查看时,它显示为 'xxx',而你必须知道你要把 Set 和 Get 放在正确的位置。
事件也是如此。是的,有事件的高级概念,但它们在语言中实际上看起来并不像事件。它们看起来像接口和适配器类,转发调用并实现接口,或者匿名内部类,或者你在 Java 中见过的那些东西。你们都见过 JBuilder 之类的工具为所有事件连线生成的那些代码,对吧?我们觉得是时候将它们添加为一等语言构造了,在底层平台以及编程语言中都是如此。
打个比方,用 C 你当然可以做面向对象编程;只是更难。你可以自己布置 v-table,假装有方法和虚拟分发等等,但这很复杂。C++ 也是如此。你可以做组件导向编程,只是更难。你必须做各种宏、IDL 文件、类型库等等。我们想要将所有这些整合进来,给你那种"一站式"的编程体验。
Matt: 你在 C# 中是如何实现这一点的?
Anders: 在 C# 中,我们实际上将其形式化为语言构造。我们有称为"委托"(delegates)的东西,它们是面向对象的函数指针。它们充当封装将控制权从事件源委托给事件处理者这一概念的核心数据类型。我们还有在类中声明事件成员的概念。
Matt: 不少人说 C# 是 .NET 的原生语言。你同意吗?
Anders: 嗯,不,我不认为 .NET 有原生语言。.NET Framework 本身定义了一个完整的编程环境抽象,包括类型系统、指令语言、执行模型、安全系统、版本控制等等。它是专门设计为多语言的。它被设计成没有一种原生语言。我们想要能够承载这种称为 C# 的新语言,但当然还有 Visual Basic.NET、C++ 的托管扩展、JScript,以及据最新统计,大约15或17种由行业合作伙伴或学术界构建的语言。
然而,确实,Common Language Runtime 的诞生与 C# 的诞生是同时的,而且在某种意义上,设计 C# 时我们有幸不必担心任何向后兼容性。但这并不意味着它更原生。它只是意味着我们没有任何"兼容性税"。但就我们实际支持的内容而言,当然,你在 C# 中能做的任何事情,在托管 C++ 中也能做,而且你在 C# 中能做的几乎所有事情,在 VB 中也能做。
过去,Visual Basic 和 C++ 之间存在巨大的鸿沟;简直是两个完全不同的世界。不仅语言不同,整个类库也不同。几乎没有任何技能可以转移。有了 Common Language Runtime,99% 是相同的;相同的执行系统、相同的类库、相同的开发模型。它都运行在 ASP.NET 中,所以如果你构建网页,周围的 HTML 是一样的。只是语法不同,而且即便如此,我会说运行时 99% 的特性都被这两种语言支持。
只有当你深入到最角落的角落时,才开始看到差异。例如,C# 支持不安全代码,而 Visual Basic 不支持。如果你真的需要深入操作指针并与这种非常复杂的旧式 API 互操作,那么 C# 可能更容易一些。另一方面,Visual Basic 支持以后期绑定方式动态调用,你可以在编译时不知道方法是否存在的情况下调用。这在 C# 中要复杂得多,因为你实际上必须使用反射引擎。你调用 'object.InvokeMember',传入方法名字符串和一个代表参数的对象数组等等。
所以一旦深入到那些角落,你可以说 C# 稍微偏向强力程序员,而 VB 稍微偏向易用性。但从大局来看,当你考虑到我们在统一平台和统一底层类库方面取得的巨大进步时,这几乎是一个微不足道的差异。
Matt: 微软的一些合作伙伴似乎在 .NET 下实现像 Python 这样的语言时遇到了问题。这是否源于 .NET 的基本对象模型与 Python 的对象模型不同?在这种情况下,虽然 .NET 是语言无关的,但它确实强加了某些属于语言一部分的对象模型?
Anders: 我认为你说到了一个非常现实的问题。如果我声称将任何随机语言移植到 .NET 上完全是无摩擦的,那是不真诚的。显然这需要一些工作。不过,我们一直与行业和学术界的合作伙伴合作,他们在实现这些语言,我们倾听了他们的问题。我们实际上因此改变了运行时。这让我们在进度表上付出了真正的时间来做出运行时行为上的这些改变。
运行时是承载的所有这些不同语言特性之间的一个"大并集"的表示。这就是为什么我们并行开发它。它完美吗?没有什么是完美的,但我认为我们取得了很大进展,而且这些语言确实正在被实现并且是可用的。是的,模型不同。很多这些语言实际上是自成一体的小环境,从未有过外部世界的概念。所以你可以实现它们,但真正的力量来自于添加一些允许你调用这些 API 的扩展。然后这个全新的世界就打开了,而你不必抛弃所有现有技能。人们在技能和已构建的软件上有巨大的投入,如果我们能帮助他们利用这些,我们就是在为他们服务。
Matt: 另一个令人关注的领域是 .NET 与 COM+ 服务的集成。例如,事务处理和消息队列并不是原生的 .NET 服务?
Anders: 嗯,有些是,有些不是。你说得对,事务仍然由 COM+ 代码处理。但想想人们用事务协调器做什么:他们在托管和非托管代码之间协调事务。如果我们假设既然发布了 .NET Framework,一切都是托管的,如果你需要与一些现有 COM 东西协调事务,那你就倒霉了------这种想法是愚蠢的。那行不通。我们知道我们必须在这个特定领域非常谨慎地演进。我们完全支持 MTS,但你说得对,当你使用它们时,你必须将你的托管类注册为 COM 对象。
Matt: 所以它们会使用 COM Interop?
Anders: 是的,完全正确,但因为我们有很好的 COM Interop,你实际上可以做到这一点,而且它能工作。MSMQ 也是如此;我们有托管封装,让处理 MSMQ 变得 vastly 更简单,但你可以从托管和非托管代码中使用它。部分力量在于它是共享的;它可以从你的现有代码和你的新托管代码中访问。
Matt: 但如果你有幸拥有一个完全从零开始的开发环境,你在 .NET 平台上设计一个独立的应用程序,你想使用 MTS 提供的可扩展性和特性,你仍然必须通过 COM Interop 吗?
Anders: 这是正确的。虽然你看不到它,但这更多是一个实现细节。你必须在注册表中注册东西,并处理一些其他事情。但这不是说你必须做一大堆丑陋的编程才能让它工作;它是相当无缝的。确实如此:像并行执行和运行时带来的一些版本控制功能,在 COM+ 中不会那么快到来。我们完全清楚这里的情况,我们肯定在研究完全托管的解决方案。但我认为互操作性将继续是一个高优先级的目标。当然,这是确保你获得完全互操作性的最实际的方式。
Matt: 但我们可以期待事务管理和消息队列成为原生 .NET 服务的那一天吗?
Anders: 是的,你可以将这个标准应用到我们做的任何事情上。我们深深致力于这个平台,你能在 Windows 上看到的任何功能,我们都在研究如何让它在托管世界中更容易、更高效地访问。不仅仅是 MTS 和事务,我们在研究所有东西。但这当然是一个巨大的工程。
Matt: 最后,你能告诉我你在巴塞罗那 TechEd 主题演讲中会讲些什么吗?
Anders: 我还没有完全确定那个主题演讲会包含什么。显然会在我专业知识的领域内,这意味着它会涉及 .NET Framework、Common Language Runtime、C# 编程语言、Web 服务的构建和消费,以及或许看看 Visual Studio 中的一些特性。
Matt: 你会在亚特兰大的美国 TechEd 上做主题演讲吗?
Anders: 不,我只做欧洲的那场。
Matt: 所以是欧洲独有的?
Anders: 是的。
Matt: 而且由一位欧洲人主讲。
Anders: 但我保证不用丹麦语讲!