语言的缺陷

前几天在《好的服务器系统》一文后讨论的时候,edguo兄建议我开一个关于DELPHI问题的话题来讨论一下,正好最近关于C的死活问题在圈子里讨论得很热闹,我也八了一篇《不值一驳》掺和了一把。现在正好抽空把两个话题整一块,就语言的问题来说一说吧。

其实早在两年前,我就曾经就语言的问题发过几篇文章《强大的DELPHI RTTI--兼谈需要了解多种开发语言》、《语言的特性如何取舍》、《有必要把什么都加到语言里吗?--谈谈 G# 和 Cω》(BTW:在后面的评论中发现,居然edguo和haitao居然是老相识啊^O^)。其实到目前为止,我的观点依然没有什么改变,我仍然认为:

没有什么语言是万能的,也不应该试图要求某种语言是万能的——这就像我曾经说过的:能包治百病的药~~~~~~~~都是假药

就Delphi 语言而言,我认为在它的定位上基本是没有什么太大的缺陷的。从Pascal到Object Pascal再到Delphi,我们不得不承认Anders是个天才,他将原生开发语言所能做到的事情几乎已经做到极致,需要再增加功能的话,改换到VM 基本上已经是必须的了。所以Anders另起炉灶打造了一个C#——代价正是放弃原生,改用VM,但这已经是另外一回事了。即使是到了现在,在原生开发领 域,Delphi仍然是最强的语言之一,特别是在动态性方面是最强的(C++虽然也有Meta,但是那个只是编译期,局限性还是很大的)。

然而事实上,Delphi还是没落了,不过这只是因为Delphi这个开发工具,而不是Delphi这种语言。

Delphi 的失败就在于它试图成为一种万能的开发工具,而它曾经的主要市场现在已经是VM语言的天下——它们的确更加适合。而Delphi的错误就在于花了太多的力 量在这个并不是很合适的领域里与它们竞争,反而失去了自己所最擅长的领域——原生应用开发。我曾经也以为用Delphi可以做出好的Web应用——事实上 也的确可以,但实在没有必要,因为有更多更好的选择。所以我现在认为,Delphi最重要的还是如何保证自己的核心功能,这也是为什么我对Turbo Delphi还报有希望的原因。

C的情况刚好相反,它只专注于自己的核心功能,从不试图去做更多的事情。

在这一阵的争论中,我只看到云风的《C 语言已死?》和孟岩的《Java替代C语言的可能性》比较有见地。

今天的C,正如云风所说,是历史的选择。然而历史为什么会选择C呢?不正是因为这几十年来没有什么其它的语言能够在C的领域里竞争出头嘛。云风认为:C 在静态语言中没有太大的竞争者其实也是 C 的悲哀

这 一点我不太同意。我不相信在C诞生后的这三十多年里没有人尝试过去创造一些更好的选择,只是它们都失败了。包括Pascal的失败也就在于它太啰嗦了,这 对于早期的硬件来说,实现编译器的代价要高于C——C的include就是当年的硬件限制留下的遗迹。还有云风举例的Ada语言,作为美国军方的指定语 言,当然是不差的,但所需的代价比C要高可能也是它没有能够成为像C这样的通用语言的原因之一。在同时代的同类语言中,C不是最好的,但至少曾经是最合适 的,再加上机会(如令狐所认为的那样,因为UNIX是用C写的,而UNIX成为了流行的OS),所以才有了今天的C。

(关于C的话题,令狐与云风通过MAIL作过一番讨论,后来令狐把那两封MAIL转发给我了,下面将会引用到这些邮件中讨论到的内容)

其实C的胜出还有一点很重要:因为用到C最多的情况就是做接近硬件的底层开发,不论是开发OS、驱动还是编写VM。而正如令狐在MAIL中提出来观点:C的语言最接近这三十年来真实的硬件模型。我同意令狐的这个看法,我认为C从诞生伊始,目标就不是要成为一种万能语言,而只是要做一个中级语言。(对C--不了解,我不知道它会不会是更好的选择,但我相信时间会对此进行考验的)

正因为C是一个中级语言,其目标是要接近底层,就意味着有些“缺陷”其实不能被认为是缺陷。云风在MAIL中指出,C用堆栈来记录局部变量的内存模 型存在不可遍历的问题,使得GC无法实现。不过我认为,以C的定位来说,内存变量遍历并不是必须的功能,为了这个功能而损失掉它与硬件的简单对应,反而损 害了自己的核心价值。虽然GC是个好东东,但对于C来说,这也不是必须的。当然也许C++可以考虑——正如C++/CLI所做的那样。

尾调用的情况也差不多,在C里可以很简单地用嵌入汇编实现的功能,没有必要加到C语言里去,这会破坏C语言本身的结构。

当 然,硬件体系是在不断变化的,但直到最近,多核被引入到桌面硬件平台之后,才算是有了一些接近本质的变化。在这个方面上,也许C的确需要一些改变(比如可 能诞生一种“并发C”语言,关于这一点,我将另文讨论),但是我仍然认为这种改变依然必须保持C与硬件的简单对应关系(比如不应该用一些隐含的手段去实现 并发),并且比起更高级的语言来说,要能够为程序员提供更多的优化可能性——即使付出的代价是可能因此丧失易用性。

其实Herb Sutter在《免费午餐已经结束——软件历史性地向并发靠拢》一文中已经说得很明白了,多核时代意味着四点问题,其中第三点就是效率优化。因为单个CPU内核的性能发展已经到顶了,所以对于应用中不可并发的部分,效率优化就显得尤为重要,在这样的情况下,C的优势是别的语言难以比拟的。

归根到底,C就是现在实际上的portable assembly language的最佳选择。

所 以我认为孟岩的说法是不恰当的,Java是不可能替代C的。现在的情况只是有一部分以前用C写的应用,因为那时除了C没有更好的选择,也许现在或以后用 Java实现会更好。但这绝不意味着它可能完全替代C,因为谁也不知道一个在Java里创建的对象在物理上是在什么鬼地方。

还有一点很关键的就是如大师所说过的:语言磨砺了我们思维的方式,也决定了我们思考的范围。Java的开发者所习惯的风格与C的开发者所习惯的风格是完全不同的,很多用C开发的应用并不适合用Java的思考方式。正如不懂中文的人是不可能讲好相声的。

但同样的,在多核的并发时代,我们需要一些能够让我们习惯并发思维的语言。(对于这一点的展开我将另文讨论)

最后说说VM语言。

我 一直不喜欢VM语言,不论是JAVA还是C#。当然最重要的原因是我所在的开发领域里,它们并不是最好的选择——做简单的桌面应用,我更喜欢用Turbo C++ Explorer;做更简单的非GUI应用,那当然是首选Python;还有Web应用,那也是Python(TurboGears or Django);至于所谓的“高级”应用,我有ABAP……

但是VM语言的长处是显而易见的,在某些领域里还是大有可为。

我只是看不惯某些VM语言的菜鸟总是把自己所从事的开发领域看作是“主流”,总以为自己用的语言是“万能”的,要P颠P颠地跑到别人的地盘上撒点野,那就活该他们要在我这里碰得灰头土脸。

事实上,每一种语言都有它自己的设计目标,每一种流行语言的设计者都比我们这些用户不知道要高明多少倍。

其实原生语言、VM语言、动态语言……各有各的用处,最关键的是要懂得在什么情况下用什么语言。要知道现在还有很多古董级的Fortran、Cobol语言的应用没有被取代。