浏览 8547 次
锁定老帖子 主题:Erlang里的OO和Java里的OO
该帖已经被评为良好帖
|
|
---|---|
作者 | 正文 |
发表时间:2007-02-14
首先,这里的OO中的Object仅指包含可变状态的Object,暂不涉及有关OO的多态、继承等概念。 一、Erlang的OO 1、保存在函数调用栈中的状态 Erlang是函数式语言,一般而言,对于事物可变的状态(参数和中间状态)尽可能局限在函数调用中处理完,在调用过程中这些状态全部保存在函数的调用堆栈中,也就是说,函数处理的是事物瞬间的状态。这时,可以说,Erlang不太关心包含可变状态的Object。 2、保存在共享内存或硬盘上的状态 当然,Erlang肯定要处理现实世界的可变状态,这些可变状态,如果是临时的,通常可以以ets形式保存在内存中,如果变化的周期较长,也可以以dts的形式保存硬盘上。ets和dts是erlang自带的数据库机制。这时,可以说,Erlang以一种基本数据结构的角度来看待包含可变状态的Object。 3、保存在Process中的状态 世界上的事物总是意想不到地复杂的,有时,甚至很多时候,上述两种方式都不太好处理事物的状态。典型的情况是UI,UI的组件需要长时间显示在屏幕上,而这些组件的状态通常是非常复杂的,比如,一个按钮,需要保存它的大小、位置、外观、文字、提示、在点击时可能需要做出的动作,等等等等。由于这类状态的持续性、易变性和异步的特点,以Object的方式来处理似乎是最合适的。目前函数式语言普遍对UI的处理比较弱。 对于这种情况,Erlang的方式是:Process就是Object。 Erlang可以把状态保存在一个Process的Loop循环中,Process之间通过Message来交互。以按钮为例: xml 代码
这段代码中可以看到,按钮的状态Wargs(Windows参数)和Fun(登记的动作)通过递归不断地传递(也是保存在调用栈中),并在接受到message时可以做出相应的改变。这时,Erlang的Object不仅具有了状态,而且还能对message做出反应,并且,它在Process中能长时间地维持。 二、Java的OO 这里想谈的是能从Erlang的OO角度来看Java的OO吗? 我的理解是:尽可能。 抛开在Java中的具体实现,假定我们能把Java的Object实例与Erlang的Process类比,那么我们可以: 1、把Object实例的Public方法调用看作是对外部message的反应(恰恰方法调用在OO的本意中原本就是message); 2、把实例方法的调用看作是把函数绑定到(外加到)一堆状态上,相当于Scope在Erlang中的message loop中的函数; 3、把实例的状态看作是在一个Loop中不断被传递的参数。想象有个隐藏在背后的Loop持有这些状态(作为参数),new操作类比为new一个Loop。 4、Class的静态方法是Erlang中的Module方法,相当于Erlang的message loop外的函数。 当然: 1、JVM中的对象实例并不对应着一个share nothing的Process; 2、想象的Loop也不真实存在。 但是,这种转换至少在想象中是可以成立的。而且,它还隐含着一种可能,就是Java的语法可能不需要太多的改变就可以让这种想象变为现实。就是说,如果将来的某一天,JVM的实现真的把每个实例都实现为一个share nothing的process,而且在背后自动地维持着这么一个Loop,再把方法调用实现为message的传递,那么你现在写的Java程序又何尝不能获得Erlang一样的并发优势呢? 有趣的是,SUN确实这么想过,但是由于对性能的忧虑而至少现在没有去做。而且,虽然有人抱怨Java里的基本类型不是对象,但在我看来,这是对的,因为即使在将来,也不可能为每个int i = 1去new 一个进程。何况,通过box,在必要的情况下还是可以把它看作对象的。 这个,也许只是将来。那么,我们现在能做什么呢? 多了解一些函数式编程的知识,并尽量将其用到日常编程中。 对于Java,至少以下几点是现在就可以开始做的:
之前: java 代码
java 代码
之后: java 代码
java 代码
声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2007-02-14
带有Thread的Object,叫做Active Object.在其他语言中也有实现.
Erlang中Message Loop State,使用的是比较频繁,但是作用远没有那么大. 对于状态变更,Erlang更多的是采用ETS/Mesnia. 从另外一个角度说,OO中的一个对象就是一个带有操作语句的微型的内存数据库. 但是OO这样的内存数据库在Distribution上有着不可克服的困难. 所以我以前说过,说Erlang的数据和代码其实是提倡分离的. |
|
返回顶楼 | |
发表时间:2007-02-14
回帖专用 写道 带有Thread的Object,叫做Active Object.在其他语言中也有实现.
没错,Erlang Way习惯于将数据和代码分离,这样可以解决大部分问题,而且带来了许多的好处。
Erlang中Message Loop State,使用的是比较频繁,但是作用远没有那么大. 对于状态变更,Erlang更多的是采用ETS/Mesnia. 从另外一个角度说,OO中的一个对象就是一个带有操作语句的微型的内存数据库. 但是OO这样的内存数据库在Distribution上有着不可克服的困难. 所以我以前说过,说Erlang的数据和代码其实是提倡分离的. 我现在在考虑Erlang实现一套UI Tool Kit的可能性,Joe对此烦恼好几年了,在他的EW11中,用的是Message Loop State,这才让我去想与Java中Object的语义上的类比。 然后再看Java Swing及其应用的代码,感觉UI程序中许多控件的状态不是一步可决的,就是说,一项操作其最终的结果可能需要异步地与多个控件或者说对象进行Message的交流,而且其行为在中间过程中是不可断的,要具备转移到多个分支的可能性,这时保存中间状态就成了常态。 Joe认为UI应当走一个控件、一个Process的方式,这时Message Loop State就成了适宜的选择。而按照我的理解,至少在语义上,OO的Object是可以接受的,而且在语义上甚至与Message Loop State是可以互译的。 我的开源程序是一个UI任务很重的项目,目前已经完成的近4万行代码中有三分之二是Java2D和Swing的,我发现如果把Object与Erlang作上面的类比,可以指导如何尽量将副作用隔离(将调用其它Object的语句与只涉及自身状态的语句分开),同时也发现,UI的复杂性使得OO的语法相对来说写起来直接些,而且是可以接受的,甚至有其优点。 当然,OO的应用需要小心避开其陷阱,比如继承的滥用和getter/setter。尤其是,如果行为与中间状态没有太多关系,就不应该将其写成对象,而应该像Java的Math包一样,全部写成函数。Java中的Collection包也应该是函数而不是对象。 OO和FP是看待真实世界的两个互补的层面,OO就像粒子,FP就像波。最终,完美的语言也许还是需融合这两种观点,但不是像现在的Ocaml和Scala这样,至少,所有的Object必须是sharing nothing的。 |
|
返回顶楼 | |
发表时间:2007-02-15
对于Erlang中如何保持状态还是不理解,dcaoyuan同学能否用Java来实现类似Erlang中保持状态的机制。比如生产者、消费者问题,用Java实现的话一定有一个容器作为全局变量来保存当前生产出来的产品,由消费者来消费其中的产品。这个容器的内容是不断变化的,如何用Java来实现FP式的编程,也就是函数不产生副作用?关于这个问题我在 http://www.iteye.com/post/190775中问过,没有得到java版的答案。
|
|
返回顶楼 | |
发表时间:2007-02-16
javavsnet 写道 对于Erlang中如何保持状态还是不理解,dcaoyuan同学能否用Java来实现类似Erlang中保持状态的机制。比如生产者、消费者问题,用Java实现的话一定有一个容器作为全局变量来保存当前生产出来的产品,由消费者来消费其中的产品。这个容器的内容是不断变化的,如何用Java来实现FP式的编程,也就是函数不产生副作用?关于这个问题我在 http://www.iteye.com/post/190775中问过,没有得到java版的答案。
引用 Producer(Consumer) ->
Consumer ! {product, self(),"Data"}, timer:sleep(2000), ping(Consumer). Consumer() -> receive {product,Ping_PID,Data} -> io:format("Consume Data ~p ~n", [Data]), Consumer() end. 在Erlang中不是所有的函数都是no-side-effection,使用 receive/send,或者读写ETS/Menisia的函数是有Side effection的. 可以修改一下Consumer 引用 Consumer()->
receive {product,Ping_PID,Data} -> Data end. Result=Consumer(). Result1=Consumer(). 所谓的no-side-effection就是说只要输入给定那么输出不变.但是这里输入一样,而输出Result,Result1的值是不确定的,取决于向Consumer发送消息的人发了什么内容. 从另外一个层面上来说,状态的产生和副作用的出现其根源来自于并行.如果没有并行,就不会有状态.比如说为何我们总是说I/O有状态,因为I/O连接的两端是计算机和操作计算机的人.CPU的运算与人脑运算是并行的,要使得CPU与人同步交互就必须产生状态和消息. |
|
返回顶楼 | |
发表时间:2007-02-19
dcaoyuan 写道 OO和FP是看待真实世界的两个互补的层面,OO就像粒子,FP就像波。最终,完美的语言也许还是需融合这两种观点,但不是像现在的Ocaml和Scala这样,至少,所有的Object必须是sharing nothing的。 似乎很难有完美的通用语言适合各种任务。Ocaml和Erlang的主要差异在于前者可选mutable数据而后者禁止。Ocaml允许mutable数据很大程度上是出于执行性能的设计要求,而Erlang禁止它显然是为了share nothing以追求高并发性。所以设计目的不同,选择也不同。 不久前Channel 9上Anders Hejlsberg等4个大牛依谈到fp和imperative语言的融合问题,主要就是c#3的设计。Anders认为提供更高抽象机制的同时也要允许人们还能按以前的做法干。这就是另外一种设计选择了。 |
|
返回顶楼 | |