最近學習了一下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的類似代碼。

 

 1public class abstract Boolean {
 2   public static final TRUE = new True();
 3   public static final FALSE = new False();
 4
 5   public abstract Object ifTrue(Block aBlock);
 6   public abstract Object ifFalse(Block aBlock);
 7}

 8
 9class True extends Boolean {
10
11   public Object ifTrue(Block aBlock) {
12       return aBlock.execute();
13   }

14
15   public Object ifFalse(Block aBlock) {
16       return null;
17   }

18}

19
20class False extends Boolean {
21
22   public Object ifTrue(Block aBlock) {
23       return null;
24   }

25
26   public Object ifFalse(Block aBlock) {
27       return aBlock.execute();       
28   }

29}

30

4 〉3 ifTrue: [Transcript show: 'Hello']就可以對應翻譯為:

 

1Boolean condition = new Integer(4).isGreaterThan(new Integer(3));
2condition.ifTrue(new BlockClosure() {
3   public Object execite() {
4      System.out.println("Hello");
5      return null;
6   }

7}
);
8
9

這個看似簡單的應用,卻帶來了兩個有深刻影響的性質。

第一,由于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做為開發語言),我發現這個問題是很難避免,于是我斷言這是面向對象技術本身的問題,現在看來不過自己所學有限,沒有真正用過純面向對象語言而已,汗顏得很啊。這里向面向對象方法道個歉,嘿嘿。