程序員的語言“艷遇史”(五)——辦公室秘書Smalltalk
(***以下小說情節純屬虛構,供朋友們在緊張編程后輕松一下,如有雷同純屬巧合,切勿對號入座***)
第五個女孩 辦公室秘書Smalltalk
一、引子
每次大學校友聚會,我和二胖都有一愛好,就是找到我們的老班長黑哥,進行一番瘋狂的摧殘和蹂躪,其慘烈程度,讓渣滓洞中美合作所都自愧不如。紅酒、白酒加啤酒灌他,稍有不從,我們立馬掏出畢業紀念照,眾目睽睽下讓他無話可說。
要知道為什么有如此深仇大恨,就得追溯到大四時代了。
二、分豬仔的畢業設計
那年頭真是風起云涌,家事國事天下事,事事激動人心。對我們計算機系學生來說,頭等大事就是操作系統改朝換代了。悶熱的暑期,電腦城里熱火朝天,小販扯著喉嚨喊,“瘟都死95,新到光盤,數量有限,欲購從速”。開假回校一看,學校里除了計算中心這個最后的UNIX堡壘,其余實驗室紛紛淪陷,全部被Windows占領。本人以前一向看不起圖形用戶界面,覺得效率狂低,認為DOS至少還可以稱霸五年。沒曾想形勢如此急轉直下,也只得認栽,開始認真看待Windows編程。
許多單位的MIS系統也開始從DOS向Windows升級,這給我系帶畢業設計的教授提供了無限商機。你想想,以組織實習和畢業設計的名義,抓一批比民工還便宜的大學生做工程,真的是一本萬利啊!為避免教授們搶生源大打出手,我系一向有“分豬仔”的優良傳統。即把畢業班學生按學業水平分幾個層次,各層次豬仔在教授們中進行均分,避免挑肥揀瘦的現象。
三、流氓也來需求調研
我、二胖等五人被發配到深圳一個倉儲物流行業的國有企業,為其開發MIS系統。我們從火車站出來,四處張望,發現業主單位居然派了個大美女來接站。沒錯,那就是我們的Smalltalk姐姐。她是項目的接口人,負責安排我們吃住,同時協助搞需求調研。
燦爛的陽光下,我戴著墨鏡,后面跟著幾條大漢,一路橫沖直撞,來到一倉庫門口。仔細對了門牌號,便推門進去。只聽著里面“啊”一聲慘叫,幾個倉管都嚇得躲到桌子底下了。我們好說歹說,連學生證都掏出來了,說自己是來做需求調研的開發人員。倉管大姐愣是不信,還好Smalltalk姐及時趕到,為我們做了證明。否則事就大了,連110都差點介入。深圳治安亂啊,這倉庫前幾天才被一伙流氓給劫了。我們一副從校園帶來的痞子打扮,倉管把我們誤認為劫匪了。難怪剛才路上行人看到我們和見鬼了似的,避之唯恐不及。我還故作親善的朝一小女孩樂,那孩子莫名其妙就哭了,她媽抱起她就跑,連掉下來的果凍都不要了。
靠!這也太有辱我們名校形象了。在Smalltalk姐的幫助下,我們立即開展了整風運動,規定了公共場合不說粗話、不穿褲衩拖鞋、走路走直線等三大紀律八項注意。違者剝奪看黃書看A片之權利(這點肯定要瞞著Smalltalk姐了)。
四、OOP之胡吃海喝頓悟篇
需求確認以后,開始著手設計開發。大家知道,我一向對C++嗤之以鼻,什么啊,效率比C語言差多了(主要是因為自己沒學通)。有個別同志還鼓吹面向對象設計方法什么的,我故作深沉,和他詳細剖析了一個MIS項目如何才能省工省力。在我這個組長的淫威下,大家最終一致選擇漂亮又輕松的VisualBasic做開發工具。
此后夜里我經常從夢中驚醒,回想起前一段給一些單位投了簡歷,其中鼓吹自己精通C++,熟練掌握面向對象方法等等,心里坎坷不安。于是潛入書店買了一些參考書,沒人的時候獨自研讀。別在面試時候露餡,臉就丟大了。唉,那時候沒什么外版書,又上不了網,國內作者基本屬于二道販子、三道販子,觀點各異,互不買賬。不看還好,多看了幾本,把我看得一腦門漿糊,原來對OOP還有點直覺,現在更混亂了。
那一段我們經常熬夜,加班加點進行項目開發。Smalltalk姐看在眼里,疼在心里。于是經常帶我們下館子,改善生活。吃在廣東,真不是吹的。海鮮大排檔和川菜是我們的最愛。在胡吃海喝中,我突然對面向對象方法有了點禪宗頓悟的感覺。
戴上面向對象這副眼鏡,我們一起洞察下館子過程。
我們要去的某餐館就是一個對象了。坐下以后,店小二送上菜單,這就是此對象的對外服務協議了,每道菜好似對象的一個方法。
“水煮活魚,四斤的一條!”。隨著小二的吆喝,方法的調用開始了,你看,還帶參數,四斤的魚。
至于菜怎么做出來,店家一般不讓你知道。人家在封裝性這一點上做得多好啊。到底用的料是死魚還是活魚,下的油是地溝油還是花生油,泡的椒是回收的還是新鮮的,不得而知。
吃完后,盤子碟子得收了洗洗再用吧,這就算資源回收過程了。有一次我們到某海邊竹排上的風味飯館吃海鮮,只見隔壁座一兄弟吃完飯,把碗飛出一個漂亮的弧線,直接奔海里去了。我們目瞪口呆,后來才知道老板心眼實,按桌面上碗的個數算飯錢。于是個別同志就出此陰招,看看,資源管理出大問題了吧。
假如某家餐館事業做大了,開始搞加盟店了,什么東街店、西門店,這就算抽象到類的層次了。最典型的例子是麥當勞。但是洋快餐也得入鄉隨俗,要考慮國情嘛。您到印度麥當勞,點個什么牛肉堡、豬肉堡,小心被人打(這就算侮辱了信仰印度教和伊斯蘭教的阿三群眾了)。所以要考慮統一性,也要顧及差異性,其他海外地區擴展的麥當勞分支就算美國麥當勞的子類了,屬于繼承的關系。
五、Smalltalk姐送的喜糖
隨著開發過程的不斷深入,需求經常更改,事情變得瑣碎,我們的士氣也日漸低落。也難怪,一群花和尚,整天抓在一起閉關苦修,又不給結算工錢,換誰不疲掉啊!再加上那年頭風云激蕩的,分心的因素太多了。
先是解放軍向東海試射導彈,形勢一度緊張,把我們這批好戰分子激動得不行,整天在賓館收看香港電視節目,開發任務也耽誤下來了。看看也就罷了,一些同志還搞沙盤推演,盡研究導彈打美軍航母了。現在我還后悔,都是人才啊,當時怎么沒向總參謀部推薦一下,臺灣問題也不會拖到現在。
臺海局勢才安穩下來,足球迷的狂歡節又到了,歐洲杯開打,接踵而至的是世界杯外圍賽。再加上談戀愛玩失蹤的,真都趕上了。進度嚴重滯后,把我這個項目小組長給氣得差點沒吐血。最后幾個模塊草草完工,質量可想而知。
后來軟件在使用過程中出了一些問題,業主投訴了。項目小組早已做鳥獸散,都忙著找工作呢。能怎么辦,只能我這個組長當冤大頭,孤身赴特區處理善后事宜。
同樣是在深圳火車站,接站的還是Smalltalk姐,可心境與上一次大不相同了。終于有和夢中仙女單獨相處的機會了,我心中竊喜。可沒幾天美夢就破滅了,我收到了Smalltalk姐送來的一包喜糖。這是哪來的牛糞,把我心中的鮮花給占了。我氣得咬牙切齒,后來一打聽,公司高干,還開一輛跑車,立馬陷入郁悶中……
六、Smalltalk語言的面向對象三法印
在那苦難歲月中,陪伴我的就是一本國防科大出的對象技術導論的書。夜深人靜,孤枕難眠,只好翻書瞎琢磨。該書介紹了C++和Smalltalk兩種典型的面向對象語言。真是有心栽花花不成,無心插柳柳成蔭,我原本打算研究C++的,沒想到后來越來越喜歡Smalltalk起來。
施樂公司PARC實驗室在上個世紀70年代,研發了Smalltalk語言及Dynabook計算機,該項目不僅是個人計算機的先驅,還創新推出歷史上首個成型的圖形用戶界面(Windows和Mac的老祖宗在這呢!),許多面向對象理念也發源于此(嘿嘿,知道重構是哪里來的了吧?)。如此摧枯拉朽的創新,在計算機科學史上真得不多見。
借用佛家術語,Smalltalk的面向對象特性可總結如下三法印:
- 萬物皆為對象。
- 計算即為對象間消息傳遞。
- 消息與對象方法間均為動態綁定。
拿著三法印,看看如何解構其他程序設計語言中常見的操作,揭露它們毫無自性,皆為虛無。
3+5相當于向3這個對象發送+消息,帶5這個參數。
條件選擇變成向布爾對象發送ifTrue: ifFalse:消息,比如1 < 2 ifTure: [100] ifFalse: [42],返回值100。
再看循環的例子,(1to: 10) do: [:n| Transcript show: n; cr ],學過Ruby的同志肯定笑了,好相象啊! 這里發生了多次的消息傳遞。先向1發送to:消息生成了一個interval對象,然后向此對象發送do:消息,帶一個代碼塊做參數(相當于匿名函數或者詞法閉包)。連續執行塊10次,把步進值作為參數送給塊,打印出來。
類也是對象,創建一個對象就是向類發送new消息,注意new不是關鍵字,只不過是個消息名。創建一個子類呢?向類發送subclass消息,動態產生。那么類的類是什么呢?元類。那么元類的類(這么變態的追問)呢?為了避免無限倒退,Smalltalk語言設置元類的類為Metaclass,而Metaclass的類也是Metaclass自身的實例。
別忘了Smalltalk的語言環境、編譯器和垃圾回收器也是一組對象,你可以查看其類定義,然后進行動態修改。就這一點,現在流行的集成開發環境也沒幾家能做到。退出Smalltalk開發環境時,可以把所有的修改包括新開發的類、對象,全部用image的方式存儲起來,下次再用。
真按這書說的,Smalltalk語言也太偉大了!我不禁心潮澎湃。但是哪里搞得到Smalltalk語言工具呢?現在直接上網down一個就行了,當時可沒這么方便,于是我又吃飽了撐著想實現一個迷你山寨版的Smalltalk解釋器,I do I understand嘛。
一動手,問題來了。我發現面向對象的這些概念離機器層面確實遠了點,不象過程語言的函數,一看到它我的腦子里就浮現出堆棧、活動記錄這些形象。這些概念也不是來自數學,而是來自現實生活的隱喻,語義上難免模糊。所以實現策略影響很大,甚至反過來重新定義語言。
如果我們把面向對象中的類想象為抽象數據類型,就會得到一種經典的實現。對象=局部環境+類指針,而消息/方法映射表存在類里面。對象收到消息,先通過類指針找到直接類,在它的消息/方法表里進行消息名匹配。如果找不到,順藤摸瓜到上一級父類中去找。找到對應方法后,把對象本身作為一個隱匿的參數傳給方法,方法中用self變量引用它。創建對象同樣是一個順藤摸瓜的過程,必須把整條繼承鏈都巡遍了,把所有類定義中的變量模板合并了,才能做出一個對象。
如果我們重視Smalltalk變量無類型的特征,那么就可以把類實現為一個生成對象的函數。對象=局部環境+ 消息/方法映射表,把方法表放到對象里。創建對象時,不僅要合并繼承鏈上各類中定義的變量模板,連方法表也要合并,形成了一個重量級的對象。創建對象花的時間變長了,可消息動態查找過程效率高了一點。順著這條路走到黑,把類的概念完全取消,就會得到原型繼承模式的面向對象流派(比如javascript之類的語言)。在此模式中,要繼承一個對象,先克隆它,然后動態修改其方法表。
上面所說的足以把經典靜態類型OOP的信仰者氣得跳腳。但還有更猛的異端,讓他們絕對吐血,那就是Common Lisp語言的對象系統CLOS。它也自稱是面向對象的(細節這里不談了,后面某篇可能會涉及)。所以說面向對象就象佛教理論,屬于術語的密林,門派林立,誰也說服不了誰。
七、尾聲
帶著淡淡的憂愁,我回到了學校。沒想到又發生了一件氣人的事。真是倒霉時喝涼水都塞牙,在我奔赴深圳受苦受難期間,班級竟然組織拍了畢業照。我當然缺席了,可是黑哥的可氣之處在于,把我和二胖弄混了,照片后面寫了我的名字,但對應的是二胖的人。我是有名無相,二胖是有相無名。這班長當的,連兄弟都搞錯了!就憑這點,我和二胖還不把黑哥修理得沒有人樣。靠,見一次揍一次。
1997就這樣跌跌撞撞的過去,我畢業了。