第3. 一切皆對象和面向對象的理論基礎
老莊是反對一切皆對象的,而TrustNo1在javaeye的一篇帖子上說:
我先說面向對象的理論基礎的問題,至于一切皆對象稍后再表。所謂面向對象的理論基礎其實是沒有的,原因很簡單,面向對象根本就不是一種計算模型。在第一次軟件危機的那個時代,對與計算機的非數值計算應用的討論以及對于可計算性問題的研究和發展,大抵確立了幾種主流的計算模型:遞歸函數類,圖靈機,Lambda演算,Horn子句,Post系統等等。其中遞歸函數類是可計算性問題的數學解釋;圖靈機是圖靈解決可計算問題的時候所設計的裝置,其后成為計算機的裝置模型,與圖靈機相關的形式語言和自動機成為了命令式語言的理論基礎;lambda演算成為了函數式語言的理論基礎;Horn子句是prolog這類邏輯語言的理論基礎。但是我們驚訝的發現,面向對象沒有計算模型的理論基礎,換而言之,面向對象根本就不是從可計算性的研究上發展過來的,那么面向對象的理論基礎的價值本身就不大。
所以我很奇怪的一個問題就是TrustNo1所謂的面向對象在80年代理論基礎上給人斃掉的說法是從何而來的?既然面向對象本質上不是一種計算模型,那么它大抵上只能歸結為一種應用技術,應用技術自然可以從各種不同的領域里得到相似的應用,那么斃掉的理論基礎所指的又是什么呢?甚怪之。
既然面向對象不是一個計算模型,那么我們可以從不同的角度推斷出OO的各種形態,老莊已經出給了從ADT引出OO的問題以及例子,我就不羅嗦了,我給一個從Functional Programming出來的例子,其實就是SICP里的Data as Procedure。
然后我們就可以
自然的,如果我調用
會得到一個messageNotUnderstand的runtime錯誤,這就是一個很自然dyanmic type的對象封裝,最早的面向對象系統Smalltalk和CLOS基本上都是這個路子,于是有一個問題,為什么最早的面向對象系統都是dyanmic type?這里就跟lambda演算有關了。
lambda演算這個計算模型根本的一個假設就是,對于任何一個定義良好的數學函數,我都可以使用lambda抽象來表述他的求值,因此無論是什么東西你能夠構造lambda抽象的話,我就能計算。這個地方東西很多,大家可以找找lambda演算相關的資料,這里我說三件事(由于lambda太難輸入,我用scheme程序代替,然后由于alpha變化,beta規約和eta規約我也用scheme偽碼來模擬。)
第一個是數值的表述,其實這個很簡單,不考慮丘奇代數的系統的話,我們可以把數值表示成單值函數:
這個東西無論給什么x都返回1,然后根據lambda演算里的alpha變換,這個lambda抽象等價于數值1。因此,對于所有的數值,我們可以按lambda演算處理。
第二個是bool的表達,也就是如何邏輯進行lambda抽象,下面我直接給出了,缺省認為大家都看了SICP,對Scheme也頗有心得。
然后我就可以做一個測試
因此,對于所有bool我們可以按lambda演算來處理
第三個是自定義類型,這里我們還是先看一個Lisp里的例子,序對。
這里依舊是high-order,我們來測試
這里大家自己用beta規約算一下,就發現的確是這樣的。這里我們又可以看到,在lambda演算里,根本沒有數據或者類型。有的永遠各種各樣的lambda抽象而已(目前已經有了帶類型的lambda演算)。這里說一句題外話,SICP里的Data as Procedure其實就是在說這個問題,不過他沒明說,而是用了一種特殊的用法而引出了消息傳遞風格,我覺得這里SICP有些顧此失彼,對于data as procedure我總結的一般形式是
綜上所述,我們看到在lambda演算里,一切都是lambda抽象,然后對于不同的lambda抽象使用alpha變換,beta規約和eta規約,表述各種不同計算。看,在面向對象之前就已經有了一切皆某某的完美的計算理論存在了。而且回顧一下:
我們有理由說,對象其實就是一個lambda抽象,所以一切皆對象不過是一切皆lambda抽象的演化,這也是為什么SICP里把面向對象稱作一種“方便的界面”而不是一種抽象的方法的原因了。那么對象和lambda抽象又什么區別呢?嘿嘿,熟悉FP的人都應該知道了,就是Side-Effect,副作用。對象允許對其內部狀態進行修改,那么這個東西就破化了eta規約的前提條件,也就是說允許修改內部狀態的東西,已經不是一個可以進行lambda計算的lambda抽象了。因此暫且給一個別的名字吧,就叫對象吧.....因此我認為,對象很大程度上是一種帶有副作用的lambda抽象。
我在有一篇blog上寫了Say sorry to object-oriented,里面給了一只用對象作分支的例子,這里就不重復了,有興趣大家可以去看一下(剛才好像在JavaEye上看到一個說法,說Everything is Object是Smalltalk的廣告語,唉,Smalltalk里的的的確確everything is object啊。)這里我們來總結一下,面向對象作為一種“方便的界面”主要解決了一個局部化和模塊化的問題,這是從lambda演算和函數編程的角度來看面向對象技術。(taowen在他的一篇blog上說,面向對象局部化了Side-Effect,我深以為然),這個東西我個人認為更加接近面向對象本來的意思,而不是由ADT里發展出來的帶類型的對象系統的那個意思。因此老莊不以為然的面向對象類型系統,我也不以為然。但是面向對象作為lambda抽象的界面,我覺得還是很不錯的。這一點在Smalltalk和Ruby里都有不錯的體現。