最近学习了一下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做为开发语言),我发现这个问题是很难避免,于是我断言这是面向对象技术本身的问题,现在看来不过自己所学有限,没有真正用过纯面向对象语言而已,汗颜得很啊。这里向面向对象方法道个歉,嘿嘿。