最近學習了一下Smalltalk,然后深深的喜歡上了這個古老的語言。Smalltalk語言只具有一個很小的語言核心,這個核心由大約10幾個關鍵字和一些基礎的面向對象語義構成。而且關鍵字都是象: . ; ( ) [ ] | := 之類的簡單符號,并沒有提供最基本控制的流程。最開始的時候這讓我很迷惑,雖然循環結構可以用遞歸表示,但是分支怎么辦?然后發現了一個很酷的特性,Smalltalk可以僅僅通過面向對象的語義來實現分支結構(其實就是State Pattern),具體的代碼如下
Boolean>>ifTrue: aBlock self subclassResponsibility
Boolean>>ifFalse: aBlock self subclassResponsibility
True>>ifTrue: aBlock ^aBlock value.
True>>ifFalse: aBlock ^nil.
False>>ifTrue: aBlock ^nil.
False>>ifFalse: aBlock ^aBlock value.
然后就可以,
4 〉3 ifTrue: [Transcript show: 'Hello']
因為在Smalltalk里,一切皆對象且從左到右求值,于是4 > 3 返回true,true是類True的唯一實例,然后就可以對它發送消息,ifTrue:,于是調用了^aBlock value.來對傳進去的BlockClosure求值。
下面是類似的java的類似代碼。
4 〉3 ifTrue: [Transcript show: 'Hello']就可以對應翻譯為:
這個看似簡單的應用,卻帶來了兩個有深刻影響的性質。
第一,由于if,else等結構不再是預定義的語法了,而與我們自己寫的代碼一樣,屬于莫一個類的特定消息,那么也就意味著,我們可以像ifTrue一樣,定義自己的分支結構。比如 aUser ifNotRegistered: [ do redirect to register page ] ifExpired: [ do redirect to active page ]
在不考慮性能優化的前提下,Smalltalk認為和 4 >3 ifTrue: [do something] ifFalse: [do somthing]
是具有一樣的語義的。并不因為Boolean屬于Kernel就有什么不同。因此控制結構也屬于一個可編程的因素,這就是Smalltalk的輕語法特性。
第二,在簡單的語法和完全的面向對象語義中,構造與馮諾依曼式語言完全等價的能力(這種能力在語法上表現為賦值,分支,迭代和子程序調用),于是我們可以完全用一致的面向對象的方法來構造軟件。
很長一段時間以來,我都認為面向對象方法論是在命令式的馮諾依曼式語言的基礎上,通過引入類型系統然后修修補補的得到的,由于馮諾依曼語言式的語言是面向操作層面上的,只是為了更好的刻畫操作計算的一個命令的序列,因此馮語言不可避免的具有不完備的語義,混亂的抽象表達以及等等一系列的問題。作為馮語言的一個大補丁的面向對象方法,我也想當然的以為他雖然有了些進步,但是基礎問題上面還是不能避免的,加之面向對象缺乏一種一致的構造方法,很多時候我們不得不回歸到命令式或者過程式的方法來構造系統,從而破壞掉一種一致清晰的思路,在過程和對象之間不住地權衡(比如Domain Model之爭),這個讓人非常的不爽。在嘗試了一些面向對象語言之后(我是在95年接觸C++的時候開始了解面向對象的,而后主要使用Java做為開發語言),我發現這個問題是很難避免,于是我斷言這是面向對象技術本身的問題,現在看來不過自己所學有限,沒有真正用過純面向對象語言而已,汗顏得很啊。這里向面向對象方法道個歉,嘿嘿。