由于赶着下班,上面是刚萌生一点思想,仓促写下的,所以可能发现不知道在说什么,或者说逻辑错漏百出。

经过一番思考后,突然开始发现原始思想有点问题,OO对立面是PO吗?于是决定思考一番后,再作评论。

是事物改变运动的轨迹,还是运动改变事物的状态?在计算机中,即是计算改变数据,还是数据驱动计算?其分别对应于控制流计算机与数据流计算机。这是对“第一性”问题回答的根本分歧所在。

正如banq所说,目前的结构化与面向对象,对事物的认知角度不一样,一个抽象为“数据结构”,一个抽象为“对象”,前者通过“算法”来改变“数据结构”中的数据,后者通过“消息”来改变“对象”的状态,但其共同点是认为事物是第一性的,运动是第二性的。

可是呢,在另一种世界观中,运动是第一性,事物是第二性。比如逻辑式,用逻辑描述运动,认为逻辑是第一性,至于条件(事物)则是第二性的,比如函数式,用函数描述运动,认为函数是第一性的,而输入的数据(事物)则是第二性的。

举个例子吧,比如男人、女人与爱情。在“运动世界观”中是以“爱情”为中心,至于男人与女人是梁山伯和祝英台,还是罗密欧与朱莉叶,这个是其次;而在“事物世界观”中,爱情不过是“男人”和“女人”之间的一种行为而已。

声明式与命令式,现在我决定还是把它们看作方法论层次上的一种划分,不再用它们表示世界观了。在banq看来,声明式是关注战略,命令式是关注战术,在uda1341看来,声明式是关注结果,命令式是关注过程。而我也认为,这可能是声明式与命令式的真正含义。

现有的面向对象一般采用了命令式范式,所以之前将其归入命令式范式中,其实面向对象也可以引入声明式范式,这大概也是banq说的在DDD推荐使用声明式。

而函数式一般是声明式的,uda1341说,“纯函数是和逻辑式没有找到很好的解决状态迁移的方案”,如果函数式引入命令式范式将如何呢?因为声明式只关心结果,不关心过程,那么状态迁移它能解决好吗?

尽管“面向对象”与“面向过程”描述事物的方式不同,但是它们都可以使用“命令式”与“声明式”的方法,比如java使用Annotation,sql可不可以认为是使用“声明式”方法的“结构化编程”呢?

尽管“函数式”与“逻辑式”描述运动的方式不同,但它们除了使用“声明式”,可不可以也引入“命令式”,关心一下状态的迁移过程?这个我不知道,因为对与这两类语言我并熟悉,熟悉的人可以给我们讲解一下。

这样根据事物与运动谁是第一性,将编程范式分为两大类,至于名字怎么取,先不考虑了。根据对事物的描述方式可以分为结构化编程、面向对象、面向进程等;根据对运动的描述方式可以分为逻辑式、函数式等。

两大类编程范式都可以使用“命令式”与“声明式”两种表达方式?有点累了,不想了,有兴趣的人接着想吧。

最后提醒一下,在想的过程中“分类的层次与分类的角度”一定要保持清晰一致,“分类的层次,是站在不同的抽象层次上;而分类角度是站在同一层次上的不同关注点上”,不然很可能出思维的混乱-:)。
[该贴被jdon007于2010-10-27 20:55修改过]

还有一点,想跟banq再交流一下。

在我的理解中,banq心中的“象”与“数”之争,是在对“事物”的认知上的不同,就像“中医”与“西医”之学。对“事物”的认知上的不同,我一直认为这只是“方法论”层次上的不同,在这个层次上,我与banq的观点可以说是一致的。

而在我心中“象”与“数”之争的的含义,是可以提升到“世界观”层次上,但要先对“象”与“数”重新定义,或者说回归它们本来的含义。在《易经》中,有“象、数、理”之说。我个人认为,象就是描述事物,数就是描述运动,而理就是描述规律。在这层含义上,“象”与“数”之争,我才觉得它们是世界观层次的争论。

之前我也说了,如果放开束缚的话,程序的构成也可以理解为“象”、“数”、“理”;“象”描述事物,“数”描述运动,“理”描述规律。在程序中,将“数据结构”可以理解为“象”的最高抽象,“算法”可以理解为“数”的最高抽象,“模式”理解为“理”的最高抽象。至于出现“名可名,非常名”的尴尬,这个《老子》他也没有很好地解决。

banq如果同意我的理解,就会察觉“象”与“数”之争,多么像“唯物/唯心”之争。我不知道这是不是“唯物/唯心”之争的本来含义,也不知道这是不毕达哥拉斯提出的“万物皆数”的真正初衷。

如果是这种层次的争论,我不会去试图说服另一方,因为我承认自己思维的局限性,谁是第一性,世界的终极本质是什么?我们能给出答案吗?也许能,也许不能。但我自己认为,在我有生之年,我是很难领悟出的,确切说,我是不相信自己可以领悟出的。至于我的解决方式,扔硬币,石头剪刀布,分歧终端机,都可以。

记不清楚了,王小波在一次谈话说及(大意):过分强调东西方思维的差异,本身可能就是想在掩饰什么。王小波的本意可能是想表达:持这种观点的人,可能想掩饰自己的傲慢或自卑。而我想说的是,过分强调东西方思维的差异,可能会掩盖掉世界的真相。

2010年10月28日 12:42 "jdon007"的内容
王小波在一次谈话说及(大意):过分强调东西方思维的差异,本身可能就是想在掩饰什么。王小波的本意可能是想表达:持这种观点的人,可能想掩饰自己的傲慢或自卑。而我想说的是,过分强调东西方思维的差异,可能会掩盖掉世界的真相。 ...

哈哈,这个话题自从清朝鸦片战争以来争论了很多年,我们不必在这里较真了,我主要侧重在软件领域的这两种思维方式的区别,思维方式是没有国界的,四色原型也属于我界定的象思维,而我把数归纳为数思维,这些都是西方世界的,所以也没有国界之别,当然这些都是我胡思乱想,一家之言。

关于中西方思维差异思考,是我个人爱好,因为到底是中国人吧,如果你看过“阿凡达”,可能会对中西方文明的差异导致的情况有一个了解,这涉及其他话题。

关于深刻思想讨论,不是一两天就能够达成一致,有分歧是好事,当然孔子讲究和为贵,所以,中国人总是将求同放在存异之前,这些我个人认为都属于中国文明的糟粕,中国文明唯有老子为纯正,孔子作为老子的徒弟,想超过老子,想具化老子思想,结果误导国人失去了对真理的探索,走上对人文化纠缠之中,自从有了孔子以后,以后的社会包括现在都是生活在孔子阴影中,包括我们现在讨论。

还是那句话,屁股决定脑袋,你屁股处于哪个时空,你接受的信息就是受限于那个时空限制,你脑袋开始思考之前就已经被人下套了,所谓你一思考,上帝就发笑,要进入思考的自由空间,就是要摆脱屁股的束缚,可是哪有那么容易呢,上帝早就在这里给你下好套了。

非常欣赏jdon007,敢于思考,知识渊博,能够碰撞出思想火花,希望随着时光流逝,在我摆脱自己屁股,如灵魂脱离自己身体可以凝视自己时,能够再体会这几天碰撞的思想。哈哈。


[该贴被banq于2010-10-28 12:58修改过]

>>“象”与“数”之争,多么像“唯物/唯心”之争

<<的确不同角度会带入不同考虑,而角度会因思维方式不同而不同。以上也是我的角度,延伸出来就会出现辩证唯物论和逻辑哲学的争论,有点像命令式与声明式(不知道有没有这两式之争呢,待后去查查看)。其实拥有以上观点也是有一个过程的,其实就是关于OO的定义,OO一直没有明确的定义,所以也没有文献直接指出它到底属于那一边。我想既然是认识世界,应该可以从世界观和方法论来划分,当然可能OO既包含世界观,也包含方法论。那么OO给了我们什么,我最深刻的是“世界是对象”,而OO中我没有看到“对象如何认识”,“对象运动”等。不过没有方法论的话,也代表认识不了世界,那来的方法论呢?就是我们本来对真实世界的方法论,为什么会用得上,因为OO具有一个特点——较接近人类认识。使用各自的方法论会出现了一个问题,认识和分析时,各自一方,很难交流,正由于这样大家慢慢就会把方法归纳统一,于是出现了很多认识与分析方法,如UML(通过动与静不断地发现类和对象,这正是一种认识世界的方法)。或者从另外一个角度说,若果OO中本身就带有方法论的话,为什么在这个带有统一性质的面前我们还会建立各自方法论和会出现各种方向、多种多样的方法论呢。也正因为OO是世界观,才会出现这么多以OO为定语的东西。

所以通过这样的分析,我才会认为OO是世界观,当然这是我一方之谈,同时也是banq所说的,我的屁股。

换角度思考的确是很难的一件事,但多个角度思考问题,才会全面。所以对一件事物作出一个全面定义或定位是基本不存在(角度太多了)。所以交流很重要,顺着对方的思路思考,可以轻松很多。也正因为交流,认识才会向全面飞跃。当然也会存在冲突的情况,怎么办,坐好屁股咯~o(∩_∩)o 哈哈

说出东西思维,并不是说刻意划分,但因为文化本身就存在差异,所以思维差异肯定存在。例如,西方思想做生意的,一板一眼,处处逻辑,什么合同、签字等缺一不可,出事了赔钱,赔不了倒闭,或者干脆进监狱。而中国呢,老板够朋友那种的,一句话“OK”,搞定,出事了大家退后一步。文化底蕴不同,也就存在很多的角度不同,西方比较个人、人权,东方比较大局。认识差异是为了更好对比和学习,忽视差异只会令自己盲目、混乱,所以为什么会把西方的运营模式搬过来会完全行不通,也就这个道理了。文化、思维各有好坏,所以不就存在东方学西方的,西方学东方的么?没有对比过的话,可以学到么?

“过分强调东西方思维的差异,本身可能就是想在掩饰什么”,其实我可以换一句“过分强调东西方思维的差异,本身可能就是想在掩饰什么”。极端的话,都是不好的。

[该贴被SpeedVan于2010-10-28 16:12修改过]
[该贴被SpeedVan于2010-10-28 16:14修改过]
[该贴被SpeedVan于2010-10-28 16:18修改过]

王小波的话没引用好,显得有点尖锐,王小波本人的意思估计更多的是“我们不必自卑”,事实上传达的也是一种积极的信息。至于我呢,只是不希望,也可能是多虑了,持有面向对象观点“看不上”持有面向过程观点的人,或者反之,这对整个群体是一种智力的浪费。

至于SppedVan说OO是世界观,我同意OO包含某种世界观,每一种方法论可以说都是在某种世界观的指导下产生。我自始至终,不同意的,仅仅是把“结构化”与“面向对象”的差异放在世界观的层次而已。将其差异放在“方法论层次”,解释清楚其差异,“世界观”其实本来就相同的的人,会更容易达成共识的,而放在“世界观层次”,犹如“价值观”不同,这样很多时候要达成共识就困难很多。

而讨论中,大家没有没太注意到另一种世界观,其实如果注意到那种世界观的也具有一定的合理性,也可能会产生很多有趣、新鲜的念头。

多谢banq的鼓励,在软件开发领域,我是只是个新兵,如果在这个行业有兴趣坚持下去,希望有机会多多接受banq的指导。

同意 jdon007 说的另外一个世界观的说法。对于命令式和声明式的分法也表示同意的。不过我是把他们作为“象数”另外一种的分法,而且是属于到达高层阶段的分法。但象数之间的区别不能因为他们而忽略。而我出现分歧意见的也是对于那条公式而已,可能我有点咬文嚼字的嫌疑,但对于“数+设计模式”的说法有点不明所以,“数”没有OO的四个基本特点,何来谈上满足五大原则的设计模式呢?所以我比较不同意这种说法。

对我来说,先从“世界是什么”来区分“数”与“象”,再从“物质(数和象,不是其他)还是逻辑是第一性”来区分“命令式”与“声明式”。对于这两种方式,个人都感到是世界观的区别。就像“唯心”与“唯物”,“辩证唯物论”与“逻辑哲学”。因为他们都重于回答“世界是什么”。辩证唯物论和唯物辩证法很相似,但他们回答的重点不一样。而“命令式”,他可以说只是一种世界观的表示方式而已,他并没有涉及到类似“世界普遍联系”,“矛盾统一”等一系列的观点。可以说它的存在类似用语言陈说辩证唯物论一样,而若要把他归为世界观或者方法论,我觉得最多只能归到它所陈述的世界观上。在“命令式”中实在找不到处理问题的方法,表示方式并不是解决问题的方法吧。而“声明式”也是在说“运动”第一性而已,但也没说明该如何处理问题。其实区别世界观与方法论,可以用它到底回答了什么来区别。
[该贴被SpeedVan于2010-11-01 10:06修改过]
[该贴被SpeedVan于2010-11-01 10:14修改过]

很欣赏speedVan对于面向对象编程在哲学高度(世界观)上的认识。但是理论上我们可以很趋近我们的理解,但是实际上我们不得不为现实的工作去让步。毕竟我们的程序要运行在计算机中,总要考虑它的特殊环境。

OO更符合我们人类的认识。适合复杂的大规模系统。面向过程的函数式编程,更适合一些具有固定目标的具体问题。两者结合应该是比较强大的。因为,虽然对象提供了抽象的设计能力,但是最终,这个设计也需要执行者。我感觉最后的执行者可能是某个脚本。

从以上几点上出发,我比较欣赏scala。

在C语言中实现类的模拟的例子。


// cool.h 头文件,定义父类和子类。
typedef struct {
char* name;
int age;
} Person;
void setName(Person* person, char* name);
char* getName(Person* person);
void setAge(Person* person, int age);
int getAge(Person* person);

typedef struct {
Person person;
char** listOfCourses;
int numOfCourses;
} Student;
void setListOfCourses(Student* student, char* listOfCourses[], int numOfCourses);
void printListOfCourses(Student* student);

// person.c 源文件,父类的行为原型的实现。
include <stdlib.h>
include <string.h>
include "cool.h"

void setName(Person* person, char* name) {
person->name = malloc(sizeof(strlen(name) + 1));
strcpy(person->name, name);
}

char* getName(Person* person) {
return person->name;
}

void setAge(Person* person, int age) {
person->age = age;
}

int getAge(Person* person) {
return person->age;
}
// student.c源文件,子类行为原型的实现。
include <stdlib.h>
include <string.h>
include <stdio.h>
include "cool.h"

void setListOfCourses(Student* student, char* listOfCourses[], int numOfCourses) {
int i;
char** temp;
student->numOfCourses = numOfCourses;
temp = malloc(numOfCourses * sizeof(char*));
student->listOfCourses = temp;

for (i = 0; i < numOfCourses; i++) {
*temp = malloc(sizeof(strlen(*listOfCourses) + 1));
strcpy(*temp, *listOfCourses);
temp++;
listOfCourses++;
}
}

void printListOfCourses(Student* student) {
int i;
char** temp;

temp = student->listOfCourses;
printf("%s' major is ", ((Person*)student)->name);
for (i = 0; i < student->numOfCourses-1; i++) {
printf("%s, ", *temp++);
}
printf("and %s.\n", *temp);
}

// main.c 主源文件,观察多态现象。
include <string.h>
include <stdio.h>
include "cool.h"

int main() {
Person* lily;
lily = malloc(sizeof(Person));
setName(lily, "Lily");
setAge(lily, 19);
printf("%s is %d years old.\n", getName(lily), getAge(lily));

Student* peter;
peter = malloc(sizeof(Student));
setName((Person*) peter, "Peter");
setAge((Person*) peter, 20);
printf("%s is %d years old.\n", getName((Person*) peter), getAge((Person*) peter));


char* listOfCourses[] = { "poem", "music", "movie" };
int numOfCourses = sizeof(listOfCourses) / sizeof(listOfCourses[0]);
setListOfCourses(peter, listOfCourses, numOfCourses);
printListOfCourses(peter);

return 0;
}

输出:
Lily is 19 years old.
Peter is 20 years old.
Peter' major is poem, music, and movie.

面向过程虽然穿着函数这件马甲,与函数式编程应还是不一样的。在面向过程中,我们总是先定义变量,而后写过程,也就是说是围绕“事物”展开思考,尽管变量表示事物,可能缺失了事物本身应具有的丰富内涵。

函数式语言有什么优秀的特性,是面向对象所缺失的呢?lambda表达式、closure机制、callback机制还是什么呢?在面向类的语言中,这些特性有相应的实现方式。lambda表达式可以通过匿名类进行模拟,closure机制与类本身就心有灵犀,颇为相似(在Javascript可以通过闭包模拟类,但存在内存泄露问题),callback机制在“策略”、“观察者”“命令”等模式都有所体现。(从这个角度看,模式有时候可以看作超越本土语言限制从而具有另一种语言能力的一个途径。Peter Noving 有篇文章《Design Patterns in Dynamic Programming》展示了在一些动态语言中天生具有GoF23种模式其中16种模式的能力。)

在围绕“事物”的编程范式中,有面向变量(如C)、基于类的面向对象(如Java、C#,C++混合面向变量和基于类的面向对象的两种能力),基于原型的面向对象(如Javascript,当然Javascript不止具备这一能力 )、面向进程的(如Erlang),对"事物"不同粒度和方式的抽象,都有其合适的应用场景,在某些场景用变量思考方便一些、在某些场景用类思考方便一些、在某些场景用对象思考方便一些、在某些场景则用进程思考方便一些。

从直观上看,目前我的认识,语言对事物的抽象或仿生应该具备三种能力:1)事物可以同时具有状态和行为,这点Java、C等做得不错,只是类是一个相对静止的概念,也丢失了事物的一些内涵;2)事物可以自我成长,可以有新的记忆和习惯或放弃旧的记忆和习惯,也就说事物可以动态增删状态和行为,这点Javascript似乎具备了;3)事物可以自我独立运行,也就说事物应该具备进程的特性,“万物并育而不相害,道并行而不相悖”,这点Erlang做得不错,Erlang支持并行、分布、容错、热升级等特性,“无锁”的特点更容易将多核、分布计算的能力发挥得淋漓尽致。

Anders Hejlsberg预测语言的发展趋势是:声明式、动态式和并发式。Anders作为语言设计者,应有更深入的思考。而我(们)作为语言使用者,只能根据一些常识进行思考。但思考的结果似乎有些相似之处:动态式表达了事物自我成长的特性;并行式是表达了事物自我运行的特性。

至于声明式,一般将函数式语言归入声明式范式。之前的讨论改变我用声明式表达世界观的做法,现在我认为声明实际只是对方法论的一种描述,描述一种隐藏how的能力。从这个角度,语言的发展就是一个不断声明化的过程。汇编语言(徒步)相对于机器语言(爬走)是一种声明式表达,面向变量(自行车)相对汇编语言是一种声明式表达,面向对象(汽车)相对于面向变量是一种声明式表达。语言的发展好象交通工具的发展一般,总是希望可以使我们更快地到达目的地。

未来语言将在对“事物”更完善的抽象基础之上,即引入“动态式与并行式”;用更“声明式”的方式表达事物之间的“相互作用”。

此外语言的抽象程度,应与人的当下认知协相调,倘若语言的抽象并没有控制或降低解决问题的复杂度,则可能成为程序员的“心智负担”,反而制约了我们解决问题的能力。

未来还可能出现“元语言”,领域专家可按专业知识,使用“元语言”生成一种贴近领域术语与概念的语言。领域专家与程序员的关系就可能变得疏远,因为其可以直接使用生成后的语言对领域进行建模并实现。而程序员将再次被进行大的分化,一部分回到程序技术本身,一部分则跳到领域中去。上一次大的分化,是软硬技术的分离,这一次分化,将是领域与(程序)技术的分离。

我们在编程的时候,总是先定义类,再来实例化对象。这看起来天经地义的举动却是违背认识规律的。也就是说,到底先有类还是先有实体。
很显然,世界上是现有了实体,才有了对实体的归类。
如果先有类,再由类派生出实体。那么这体现了一种单一且静止的世界观。单一性表现在,实体只能属于某个类;静止性表现在,实体无法发展,无法实现角色转换等。
我们对世界上的实体,总是多重的。banq以前举了个例子,你本人在家是家长,在学校是老师,在工作岗位是员工。家长、老师、员工都是不同的类,而这些不同的类都指向同一实体。因此,实体不是单一的,从类实例化为对象的做法是需要改进的。补救的办法是在由不同类实例化为的对象中,增加一个灵魂属性,只要灵魂一样,就能判断其为同一实体。
我认为正确的方法是先有实体,再来归类,实体是主,类是辅,先有实体,再有类。因此javascript才强调原型化,与类无关。
实体的发展性体现在随着条件的不同,实体的归类会发生变化,比如一个人从小到大会经历小孩、成人、老人三种不同的分类。同一实体在不同阶段也会有不同的分类。

----------------------------->
数据结构的重点在于存储,即将如何存储数据:这里,我不想将数据结构仅仅理解为表、树、图,对我来说变量、对象等凡是可以容纳数据的东西,都可以理解为数据结构。

这一点我不赞同,我理解的数据结构如下:
数据结构的重点就是于他本身这四个字,即数据的结构,数据的结构是怎么组织的,然后怎么应用的。数据结构的重点不在于存储,而仅是多数情况体现于存储而已。
[该贴被leoyu于2010-11-12 16:26修改过]

To leoyu
看了你的解释,觉得你我的理解并没有什么出入。所谓数据结构,就是构建结构以组织数据,组织数据是有效地保存数据,当然也是为了便于应用。如果你看了上面的一些讨论,可以看出我对数据结构的理解其实很简单:数据结构这个概念是表示what的含义,是对事物在程序世界中的最高抽象。在不同的语言范式中,数据结构的概念可用变量、对象、进程等进行具体化。

To redorange
javascript中的对象挺有趣,刚开始我用类进行思考其继承机制,总感觉不自然,纠结了好几天,查阅了语言规范,才放下类,了解了其原型的思维方式。这是学javascript唯一感觉不太适应的地方,至于其他闭包、lambda表达式、callback机制等函数范式的特性,倒是容易接受。除了支持属性的动态变化,javascript还有一些奇特的现象:函数也是对象,对象是哈希表(数据结构)。总之,挺好玩的一种语言。

在函数式的世界观中,描述事物的变量(或符号)是一次性的,赋值过一次就不能再赋值了。比如你令x=1, 就不能再x=x+1了,当x用完,就销毁。这是以“运动”(函数或逻辑表示)为第一性的世界观,事物不过是“过眼云烟”,数据驱动计算后,就立马销毁。在这种世界观下的指导下,自然是没有副作用,因为事物只能有一种状态(赋一次值),也就不难理解为什么纯函数对同样的输入只能有一种结果。

在我看来lambda、closure、callback等函数式范式的特性,还不能体现其世界观,只是一些操作层的方法,可以移植到以“事物”为中心(面向变量或面向对象)的范式中去,但也许不会产生革命性的变化。如果要真正结合两种不同的世界观,就需要对其进行明确的定位与分工。如Erlang,在外部,以“事物”为第一性,将“事物”抽象为“进程”;接着在“进程”内部,以“运动”为第一性,将“运动”抽象为“函数”。

现今主流的基于类的面向对象,对“事物”的抽象尚不完善,它只是绑定了变量与过程,但并没有刻画出“事物”动态生长、自我运行等特性。所谓“道法自然”,面向对象对事物的抽象或仿生,并没有尽如人意。

如果面向对象要与函数式结合,可以借用Erlang的设计智慧,在对象内部采用函数式表示,也许这样将带来一番新兴的气息,副作用也将消失(不过副作用真的有百害而无一利?这个现在我还不能确定。但可以肯定地是,没有副作用,事物内部状态的表示将会呈现出不同的形式)。

还要重复的观点是,即便引入函数式,“面向对象”对“事物”的抽象仍不完善,也许还需要引入动态和并行的能力,而如何有效、优雅地融合这些能力,这就需要语言设计师的智慧了。