神和公理

  在那篇《从ruby的面向对象说起》的最后我说到了一些关于世界起源的问题。有人回复问神是谁创造的,这是个很有意思的问题。咱先回到ruby的世界。对于语言层,对于那些变量、常量等等符号而言,解释器就相当于是神。他操作了语言层的一切。而我们用语言写程序的时候一般是不会想到虚拟机的,而在代码里,无论如何,都无法超越虚拟机的限制,也是看不到“虚拟机”这个东西的。虚拟机所能做的就是语言所能做的极限。

  但是ruby虚拟机也是一个程序,它是运行在电脑硬件上的。一个二进制程序,哪怕是完全用汇编,甚至机器代码写的,直接操作存储器,寄存器,执行指令,操作外设,但是这些指令实际却是由CPU内部的微指令完成的。这些硬件的运算器,存储器的功能则是由更细化的触发器,门电路等等实现的。这条路甚至可以追溯到在硅锗上流动的电子。ruby解释器这个神可以说就是CPU,而CPU之上也还有许多层次。那么这个层次有没有头呢?在半导体这层,为什么他们可以单向导电?为什么会有放大效应?这是原子的物理特性决定的。这似乎就到头了因为还没法对物理特性的原因说什么。

  物理和其他科学都是人类发现的,或者是总结出来,通过实验验证,或者由现有的只是推演,都是在我们这个世界里进行的。或许就像前面所说的,无论我们对世界的认识增进多少,都只限于我们这个世界,而对于这个世界之外的世界我们是很难去认识的。就像Matrix里的人,根本不知道自己是在机器里。如果说我们这个世界存在某个“神”的话,这个“神”是否是创造出来的,是由谁创造的,这是我们没法知道的。

  咱都学过几何学。几何学的基础就是欧几里德的5个公理。从这5个公理可以推导出整个几何学体系。而这5个公理却是不能被证明的。或许对于几何学体系来说,这5个公理就是“神”。实际上,这些公理是建立在我们的意识深处的。关于点线面,我们都有一个自然而然的认识。或者说,这些公理既无法证明,也无须证明。对于那个可能存在的“神”也是如此,“神”在我们这个世界之上的,在我们这个世界的体系里,又如何能对上一层次的事物进行证明呢?还是不要去想太多关于“神”的来历的问题吧,或许就像公理,是无法证明也是无须证明的。

php的interface == 鸡肋?

话说当年,php5诞生的时候,向java,c++学了好多面向对象的语法元素。其中就有interface。在java圈子里,主流的观念是要面向接口编程而不是面向类编程,将接口与实现分离。记得在Spring in Action的例子里,要创建一个骑士对象,首先写一个Knight接口,里面定义了骑士可以做什么。具体怎么做则是在类KnightImpl里实现的。看上去似乎有一点麻烦。不过java大牛们教育我们,这是为了更好的灵活性。这样使用骑士的时候不用关心这是个什么样的骑士,而且可以在不修改代码,只修改工厂的配置文件,就可以用另一个实现来替换现有的实现。更寻常的说法是,比如Map接口,通常我们使用一个映射表的时候只要能够满足键值对应的操作就行。我们可以根据具体需要选用哈希表实现或是查找树实现,甚至自己定义一个存放在数据库中的Map。简单的说,接口定义了一组操作,实现了某个接口的对象也就能提供这个接口规定的一组操作。接口就像是一个协议或者说一个标准。这么说来,interface应该是一个好东西,似乎是面向接口编程所必不可少的,interface不就是接口的英文词么。那这篇文章的题目又是怎么回事呢?

还是拿例子说话。
interface Computer{
    function add($a, $b);
    function minus($a, $b);
….
}

class Mainframe implements Computer{
    function add($a, $b){
        //…
    }

    function minus($a, $b){
        //…
    }
}

class Calculator implements Computer{
    function add($a, $b){
        //…
    }

    function minus($a, $b){
        //…
    }
}

不管是大型机还是小计算器,都可以算加减法。想要算加法的时候只要拿一个实现了Computer接口的东西就行。比如
function doAdd(Computer $c, $a, $b){
    return $c->add($a, $b);
}
看起来不错。不过能算加减法的不仅仅是那些用电的东西。我国古代劳动人民的智慧结晶——算盘也能算加法。那么如果要拿算盘算加法,就要有一个算盘类。那这个算盘类该不该实现Computer接口呢?这个算盘似乎也算不上是一个计算机啊。或许该另外建立一个Calculatable的接口,让计算机和算盘都去实现这个接口,这样似乎就不错了。有时候我们只需要用到Calculatable的一部分功能。比如Calculatable定义了基本的加减乘除,但我们买菜算账的时候通常只需要加法。这时候如果用Calculatable的话就需要接受一些无用的东西。再用一个php的SPL里的例子。SPL里有一个ArrayAccess接口,可以让对象像数组一样用下标去访问。这是一个很有意思的语法糖。不过有时候只需要按下标读功能就可以了,但是为了要满足规定,还是要把ArrayAccess接口的所有方法都实现一遍,于是就要写好几个throw new Exception(‘xxx is not writable’);之类的东西。这实在有点罗嗦。

为什么不换一个写法呢?扔掉那些interface,直接写
class Mainframe{
    function add($a, $b){
        //…
    }

    function minus($a, $b){
        //…
    }
}

class Calculator{
    function add($a, $b){
        //…
    }

    function minus($a, $b){
        //…
    }
}

class Abacus{
    function add($a, $b){
        //…
    }

    function minus($a, $b){
        //…
    }
}
在需要计算的时候,也不用限定一定要是Computer,把对象直接扔过去。
function doAdd($c, $a, $b){
    return $c->add($a, $b);
}

如果在试图在一个不能算加法的东西比如易拉罐上执行add,解释器自然会报错。也就是说,只有满足接口的对象才能够正常运行。你看,不用interface一样可以实现面向接口编程,而且更加灵活。

不用interface搞面向接口编程这听起来还是有点玄乎。毕竟这个interface就是接口的英文单词啊。好吧,interface确实是英文单词,但并不代表interface这个语法元素就等价于接口。就好像把狗的尾巴也叫做腿,这狗也不是就有了五条腿。interface只是叫了这个名字而已。当然,interface在一定程度上也为面向接口编程提供了方便,比如提供了编译期的检查。而且对于强类型语言来说,这样的语法元素是很重要的,比如java。而对于弱类型语言,比如php,却不是必须的。而对于一些更动态的语言,比如python,ruby来说,更是很难相容的。

 

周日去看展览拍的照片

周日去看展览(门票还真贵),在里面逛了整一下午。已经是走马观花般地看了,还是没怎么看全。说起来也好多年没去展览馆了。这次发现,这原先叫做中苏友好大厦的楼是这样大的,当作宫殿也是很不错的。展品的照片就不发了,这里贴一些楼的照片。

 

 

从ruby的面向对象说起

ruby是一个完全面向对象的语言。在许多其他语言里不是对象的东西在ruby里也都是对象,比如整数。更神奇的是,类也是对象。为什么说神奇呢?看一下下面的代码:

class A
end
puts A.class

结果是Class。可以看到,类A 也是一个对象,它是类Class的实例。接着看

puts Class.class

原来Class是Class类自己的实例。

puts Class.superclass
puts Module.superclass
puts Object.superclass
puts Object.class

类Class的爸爸是Module,Module的爸爸是Object。而Object是所有类的祖宗。但是类Object还是类Class的实例。很神奇吧。

我们知道,对象是类的实例,是由类创建的。而在ruby中,类本身也是一个对象,这就形成了一种鸡生蛋蛋生鸡的循环。似乎这是周而复始,无穷无尽的,就像下面那幅埃舍尔的名画

这两个相互描绘的手就像是ruby中的类和对象。两只手相互描绘在现实世界里是不可能的。那么在ruby中,又是如何打破这个僵局的呢?其实很简单,这两只相互描绘的手只是一幅画而已。而让两只手相互描绘则是画家。在画面内部无法解决的矛盾跳到画面外面就很简单了。在ruby里也是如此。在语言层面,类和对象似乎也像是这两只相互描绘的手,但不要忘了,还有一个ruby虚拟机的存在。一切的对象都是由它创建,而语言里的ClassName.new并没有直接创建对象。在一切的开始,虚拟机创建了Class,Module,Object,之后,这三个东西就可以滋生出整个对象世界。虚拟机就像是至高无上的神,创建了整个世界。但是在一个ruby代码的世界里,能看到的却只有对象,而不能直接看到虚拟机的存在。我们可以写完全面向对象的代码,而不用去操心这些对象究竟是怎么来的。

回到现实世界。不知道大家有没有想过我们的现实世界是怎么来的。根据被普遍接受的物质不灭理论,物质不会消失,也不会凭空出现。那么这些物质最初又是怎么来的呢?话说我们的宇宙是由一个很小的核心爆炸,不断膨胀而产生的,又话说宇宙在膨胀到极限后又会重新收缩,又变回一个很小的核心,周而复始。那么这一切又是如何开始的呢?在这个宇宙之外又是什么样呢?如果这些问题存在答案的话,要么接受一个创造这一切的“神”的存在,要么就只能说,物质是无须创造而自然存在的。