June 12, 2007

胡侃:面向对象思想的进化

本文作者还是那个无名小辈 lichray。他在考查了一些语言和历史之后,觉得有必要谈一谈自己对面向对象思想的一些诡异的想法。文中会提到许多编程语言,不过当然了,重点在于思想,文章不是用来推销语言的。


面向对象编程思想的提出已经不是几年而是几十年了,考查其思想的变化,一方面是对现有语言的一些评判,另一方面,也算是对前辈计算机科学家的缅怀。 ——题记

Kristen Nygaard在1962年发明的 Simula 语言现在被认同为世界上第一种明确实现面向对象编程中某些“必要”元素(比如 class)的语言。Simula 是从 Algol 发展来的,可以说,是一种增加了 class 这个数据类型的 Algol,并将参数传递的默认模式从“按名调用”换成了“按引用调用”,还提出了根据类型确定初始化过程的方法。
从 Simula 的时代开始,科学家们在解决软件复杂度方面的思路开始“异常开阔”——当然也有资深的老派牛人们不这么认为。比方说 Peter Norvig,写了[url="http://norvig.com/design-patterns/"]Design Patterns in Dynamic Programming[/url]一书来反驳。他认为设计模式早已体现在以 Lisp 为首的一批语言中了,根本不需要什么面向对象。但我还是跟从偶像 Alan Kay 的观点。某些时候,把一种特定的编程风格做进语言里也是必要的。
言归正传。Simula 之后的语言开始试图把 class 作为编程的基础,并提出了一系列出色的、基于类的编程风格,最终确定了“万物皆对象”这一面向对象理论的“终极思想”。于是,Alan Kay 的 Smalltalk 在 70年代诞生了。它是世界上第一个真正把面向对象作为程序组织基础手段的编程语言。它首次明确实现了“消息”和“继承”这两个重要概念,对于“封装”和“多态”也给出了里程碑式的解决方案。在 Smalltalk 程序中,一切程序元素(除了词法元素)都是对象,一切操作都是消息。而且,Smalltalk 的实现本身就是用 Smalltalk 写成的,这也就意味着,对于一个 Smalltalk 程序来说,它的底层也是以面向对象为基础的。直到现在,也只有 Self 语言有资格在面向对象的程度方面与 Smalltalk 一较高下。
Smalltalk 在成为里程碑的同时,也成为了分水岭。Smalltalk 之后的面向对象语言的发展方向分成了两条路:一是继续把 Smalltalk 中封装的概念扩大化,为程序员添置更多的约束,以支持所谓的“大规模开发”的需要;另一方面,一些人主张继续理解面向对象的原理,为这一思想添加数学上解释,而不仅仅是“拿来主义”,使程序员更不易出错或“分神”。
正像大家所猜测的那样,前者指的是以 C++ 为代表的、坚持以命令式语言风格去实现面向对象的“有类”语言,后者是以 Self 为代表的、准备以函数式语言风格去理解面向对象的“无类”语言。
有类语言中,C++ 是曾经的“蔚然大宗”。它最初的名字是 C with class,很显然,一开始只是想对 C 作出像 Simula 之于 Algol 那样的修改。但是,C++ 诞生的时候(1983年),也是 Smalltalk 80 产生的时代,也是 Ada 语言正在开发的时代。在享受了 Smalltalk 提出的类方法、对象方法、私有方法等等语言设施之后,C++ 提出了3个为后来的有类语言广泛采用的关键字:private,public,protected。不避讳的话,可以简称3P。这种区分相对于 Smalltalk 来说略少了一点,但事实证明,在实际的抽象中是够用的。另外,C++ 还从 Algol68 (这只是一个失败的旧事物罢了)那儿学来了运算符重载,还有 Ada 中的泛型和程序包。堆砌了太多特性的 C++ 显得有些不堪重负,而且失败的教育(总是拿它当 C 的升级版讲解!)、失败的实现(尤以 Visual C++ 为甚)也是它后来在开源界不那么受欢迎的重要原因。C++ 之后的有类语言开始了消减多余特性,理清思路的努力。
紧接着 C++ 之后出现的语言主要有 Objective Pascal 和 Objective-C。后者是 Mac 公司的拳头开发语言,前者是什么?就是 Turbo Pacal 中的 Pascal 语言。二者试着给古老的语言们添加新的元素。前者只是很客气的添加了 new 和 unit,特性不足;后者的转型是成功的,但说句题外话:想象一下 C 的基础上直接加上 Smalltalk 的消息传递语法,这就是 Objective-C 的语法设计。
Java,原名 Oak。这个名字现在已经处于“无敌”状态,去年已经在语言排行榜上 K 掉 C 当上了老大。Java 没有什么新东西,正如上文所说,只是一个消除了多余特性后的产物。成功的原因,一是时代的召唤,而是官方实现的基于虚拟机的跨平台特性。虚拟机早已不是什么新事物了,不过有大公司出来宣传确实是新鲜事。也许是受了微软的影响,大多数普通程序员更愿意那种喜欢被某个大公司“罩着”的感觉,于是纷纷用起了 Java。历史就是这样,听不到你的嗟呀。
Java 火起来了,各大计算机方面的媒体上充斥着 Java、OOP 等等的字眼,仿佛面向对象只剩下 Java 一种模式。各种语言纷纷改头换面,以适应“新时代”的要求:Perl 加上了4P(package 也算一个);Objective Pascal 摇身一变成了 Boject Pascal,再改名 Delphi;Basic 名字前加上了 Visual,后来后面又加了 .Net;C++ 把 ++ 改成了 # 号;就连一向对面向对象嗤之以鼻的 PHP 都被迫升到了 4.0、5.0;我的“母语”Action Script”版本也升到了2.0、3.0。
在有些人眼中,这是一场“意义重大”的变革;但在我眼中,这是一场灾难。
因为,在某个角落,无类语言们正在为寻找面向对象的数学理论基础而努力。为什么要寻找数学理论基础?这个问题早在70吗=年代就已经不是个问题了,而现在居然还有人不明所以。有类语言和无类语言的区别,就像是命令式与函数式之间的区别,就像是图灵机和 Lambda 演算之间的区别,就是一字一次的编程和面向整体操作的区别,就是 Bug 多和少之间的区别,就是单线程与高效并发之间的区别,就是必将灭亡的旧事物和必将走向辉煌的新事物之间的区别……这么多,还不够吗?
无类语言从已有的 lambda 演算理论中寻找适合解释面向对象思想的部分。1986 年研究完成的 Self 语言首先抛弃了 class 关键字,从对类和对象这两个基本问题上做文章。“万物皆对象”,类就是对象,但用它可以产生对象;怎么产生?通过复制已有对象产生。这种手段称为“基于原型的面向对象程序设计”。Self 之于无类语言,相对于 C++ 之于有类语言。它是无类语言中的蔚然大宗。但可惜的是,Sun 公司的 Self 实现几乎没有进步;Smalltalk 可能因为受够了 Java 之流自称继承了自己,认为 Self 是它唯一的“知心朋友”,发起了一个叫做 Morphic 新体系,算是对经典的延续。
Self 之后,1993年出现了 Lua。Lua 是无类语言的一个特别“函数式”的版本,在继承了 Scheme 所有思想之后,消灭了专有 List 这一数据结构,全以哈希表代之,并出色地解释了许多程序表示上的一些不太明朗的问题,还区分了消息发送和普通函数调用。Lua 不论从那个角度(科学或者商业)来看都是成功的,是无类语言中的佼佼者。
Lua 之后出现了 JavaScript,原名 LiveScript(1995),国际标准收录名为 ECMAScript。JavaScript 与 Java 诞生于同一时代,生不逢时的同时又生而逢时。说它生不逢时,是因为在 Java 的盛名之下,不负众多程序员的“众望”,被他们指责为“假面向对象”;说它生而逢时,是因为,它总算没在一浪高过一浪的 class + 4P 的嚷嚷中倒下,成为我们最为熟知无类语言。它实在是太优秀然而又太谦虚了:它秉承了 Lisp 家族的一贯传统,能够用数据表示程序本身(JSO);它又有足够的函数式编程特性,但它谦虚地称之为 function;它用复制对象再用 new 关键字 apply 构造函数的方式漂亮地解释了类和对象的关系;相对于 Lua 取消了消息发送和函数调用之间的界限;在没有任何 4P 关键字的情况下还能用逃逸变量理论实现 4P 的所有特性(不要被 dojo 之类的库蒙蔽了双眼)。几乎是一个完美的 Self 的继任者,但还是那句话,真正会 JavaScript 的人不多啊。
至此,无类语言的发展似乎已经很令人满意了,理论似乎已经成熟,只剩下一个问题:函数本身是一个什么样的对象?E 语言(1987,提出很早,实现太晚)回答了这个问题。答案很简单。函数是对象的一种,对象和方法都是 lambda 算子,如果你愿意,又可以把函数的函数体再表示为对象的一个方法!看起来这个答案不那么起眼,但它确实让人们领教了 lambda 演算在抽象层次上的嚣张。同时,E 语言还大胆地加入了对象继承的概念——一个对象可以像类继承一样继承其它对象的属性——因为这仅仅是 lambda 算子的扩展罢了!
但是,无类语言的进步不会就此结束,还有更多、跟有力量的无类语言产生,比如 Scala,一个给无类语言添加了 ML 中的静态多态类型判定和惰性运算的变态……
历史就是这样一个聋子,听不到你的嗟呀。不过,但愿后人会从这些嗟呀中借鉴到很多。

注:还有两个很牛语言没提到:Ruby 和 Python。其中前者学 Smalltalk 学地精神分裂,去掉了 Smalltalk 的强大 IDE 之后居然一炮走红;Python 是个不知道该站在那一边的语言,既没有 3P 又知道逃逸变量或 block 是什么,惨兮兮的。

2 comments:

Mountain said...

cool!

lonelyfox said...

你的多数观点我都觉得有道理,但是对于Python,你的评语恐怕值得商榷。Python的设计哲学在于不“要求”编程者使用何种paradigm,而是提供多种paradigm以供编程者选择。此外“simple, easy to learn ”也是其设计宗旨之一,可能这样的语言都多半不合你学院派的胃口。

其实是来要求跟你做个链接的,省得找起来麻烦。