backuup

版权声明

backup:

作者:王垠


  版权声明

有人来信告诉我,有些人把我最近的一些文章贴到了 CSDN,引起很多人评论,其中 90% 的人都是骂我的,所以建议我以后还是多发点可以提高大家“水平”的东西,不要发“纯吐槽”的文章。我收到这样的邮件已经不是第一次了,我并不欣赏这类邮件。

首先必须指出的是,我讨厌“吐槽”,“黑”,“喷”,“给力”这类词汇。我认为这是对汉语的污染和中国文化没落的表现。以至于任何使用这些词汇的人会立即招致我的反感,被作为没文化的人对待。另外我批评那些现象其实是为了给许多正在经受同样经历的人一些鼓励。就算我经历过它们,也过去很久了,现在跟我一点关系都没有。要是没有一点为民除害的侠义心肠,我干嘛要说那些。另外我很久不上 CSDN,各种 BBS 以及其它论坛了,也绝不会把文章贴到那些地方,所以这笔账你们应该跟转帖文章的好事者去算。博客不是用来为别人服务的,博客 = blog = web log,就是用来记录自己想法的,是给有同样价值观的人看的。在自己的博客想写什么完全是我的自由,没有人有资格要求我写什么或者不写什么。没有人请你们来这里受气,网上可以找气受的地方多的去了。自己要来这里看又不高兴,那就只能怪有些人自虐了。那些不喜欢我又 follow 我微博的人,就只能叫做心理变态了。

还有一些人就是脑子里逻辑秀逗的那种。比如,我批评了某个技术,他就说“你说这个不好,那个也不好,你让我用什么!”我还从来不知道我的话有如此威力,可以把有些人逼上绝路。谁让你听我的话了?我说什么是我的自由,你用什么当然完全是你的自由。而且我是站在很高的位置说这些话的,一个普通程序员恐怕很多时候得受制于所处的环境。另外一些人喜欢说我是“理想主义”,可是他们没有看到,我说出来的“理想”,全都是我经过试验,知道有把握实现的东西。这种人跟我以前的几个老板一样缺乏安全感和想象力,可是我每一次都做出他们认为不可能的东西。大部分人的知识是如此的脆弱,不堪一击,因为他们是靠死记硬背学会的。而他们对那些东西是如此的执迷不悟,以为拿出一些唬人的名词就可以吓到我。我的知识是很不一样的,几乎都是自己琢磨出来的,所以我不但知道它们是什么,我还知道它们是怎么想出来的,所以我经常能看到其他人(包括权威在内)都看不到的东西。这貌似跟某些人很像呢?你猜对了,是 Richard Feynman 和 John Nash。由于受到他们的启发,我跟他们有非常类似的特征,但可惜的是跟 Feynman 不同,我不想把这些推导的过程告诉别人,我懒得跟人证明我的说法。我只是像先知一样把结论说出来,不信的人自己去碰几次壁就知道了。

实际上,我并不认为网上的评论来自人类,就像下面这幅图里画的,它们其实只是来自一些老鼠一样的生物,所以我一点都不在意的。这就是我为什么不开放评论的原因,并不是因为胆小,而是因为我比较重视卫生。你看 Donald Knuth 的文章开评论吗?他连 email 都不收,都是他的秘书有选择的打印出来给他看。他是怕你们骂他吗?他只是没空跟你们说话。

不过鉴于如此,我确实没有必要公开分享什么东西了。90% 骂我,说明只有不到 10% 还值得我为他们写点什么,我也受够了很多人在微博上阴阳怪气的,所以现在发布一个正式的,邪恶的,类似 Unix 当年作法的《版权声明》:

本网站的文章,不管是赞扬,批评,还是技术性的探讨,都是具有很大价值的内容。虽然一直没有版权许可声明,但是根据国际版权法的缺省值,这里曾经发布过的所有文章内容都属于版权所有(All rights reserved)。除了个别经过许可,任何其他个人和网站都不得拷贝或者转载。由于最近发现大量的非法转载现象,以及很多获取这些非法内容的人的不知好歹的评论,现将所有内容永久关闭,以免知识产权受到更加严重的侵害。

最近还察觉到一些业界人物对本人英文网站内容进行剽窃而不加引用的现象,所以yinwang0.wordpress.com 和相关的 www.slideshare.net/yinwang0 也做出了相应措施,关闭了高知识产权部分的内容。另外,微博,twitter,以及知乎上对一些问题的答案也一并被删除。

届时本网站的律师将向所有非法转帖本站文章的站点发出停止侵害,要求赔偿的通知。赔偿金额根据严重程度从一千美元到上百万美元不等。另外还将对学术界的论文发表做出监控,防止剽窃而不引用现象的发生。对的,你必须 cite 我的 blog,如果你写论文之前看过它的相关内容。

之前作出的任何表扬或者批评,以及推荐的任何东西,从今天开始全部作废。如果因此误入歧途,走了弯路,本人概不负责。注意这并不等于妥协或者收回曾经的批评,只不过这些批评从此不再免费。批评是一种非常有价值的东西,所以从今以后我不会再免费批评任何程序语言和技术。有人为它们浪费时间浪费钱,根本不关我什么事。所有要求对某种程序语言,操作系统,数据库或者其它新技术做出评价和指导的个人和单位,都必须支付相应的费用。

另外,PySonar,RubySonar 和其它一些代码的版权从今天开始由 BSD 改为 GPLv3,从而禁止被用于不开源的软件。这一方面是由于它们的极高知识含量和创新程度,极少的依赖关系和不可匹敌的地位,我不需要利用 BSD 这样相当于拱手送人的版权来让它们“流行”。另一方面由于我完全独立的做出了这些东西,没有其他人做出过重要的贡献,如果有人拿去盈利又不想开源,当然应该支付一定的费用。Yin 语言以及其它一些项目,由于使用了更精深的技术,则进入了私有状态,它们的设计全部成为机密。

撤回这么多的好东西,我深表遗憾,但丝毫没有内疚。我曾经把它们放在外面,可惜好心没好报,所以就收回来。所谓的“开源精神”或者“分享精神”在我心目中的地位已经丧失殆尽。在资本主义社会鼓吹这些的人一般都是另有目的,所以世界上的资源才聚集到了极少数人手里。技术越是进步,工作就越是稀少,人民的生活就越是艰苦。所以开放自己的知识并不会让世界变得更美好,而只会让更多的人失业,变得一无所有。你们应该感谢我开发 Yin 语言及其相关操作系统和数据库的进度缓慢(我只是时不时弄一下),否则当它问世的那天就是程序员和系统管理员开始大规模失业的时候,因为这将是一个可以让老弱妇孺都能编程的系统。感谢现在乱七八糟过度复杂的技术,感谢 Unix,感谢关系式数据库和 NoSQL,感谢面向对象方法,感谢 web,让广大程序员和 consultant 继续有饭吃。阿门!

资本主义已经严重的阻碍了人类文明的进步,人类历史上最严重的危机正在越来越快的临近。然而不幸的是,我专长的东西对此无能为力,反而会加快它的到来,所以我决定停止散布精髓的知识,让这个行业继续混沌下去。

(附加声明:这里的内容与 Sourcegraph 无关,我在这里很快乐。)



一个对 Dijkstra 的采访视频

backup:

作者:王垠


  一个对 Dijkstra 的采访视频

(不能访问 YouTube 的人可以从这里下载 MPEG1,300M)

之前在微博上推荐了一个对 Dijkstra 的采访视频,看了两遍之后觉得实在很好,所以再正式推荐一下。如果你不清楚 Dijkstra 的贡献,那么就想一想自己用的程序语言里面司通见惯的“递归函数”是哪里来的。其实当年递归函数是 Dijsktra 和另一个人不顾委员会里众人的反对和怀疑,坚持要放进 Algol 60,所以后来才进入了 Pascal,C,Java 这样的语言的。那个时候 John McCarthy 不在场,不然的话就会有三个人支持了。

现在看来,任何一个语言里面没有递归函数都是不可思议的事情,然而在1950-60年代的时候,居然很少有人知道它有什么用!所以你就发现,所谓的“主流”和“大多数人”一直都是比较愚蠢的。现在,同样的故事发生在 lambda 身上。多年以后,没有 lambda 的语言将是不可接受的。

在这里只摘录他提到的几个要点。某些观点也许不是最好的办法,但我确信其中有非常值得学习的地方。

  1. 软件的版本号 2.6, 2.7, ... 都是胡扯。本来第1版就应该是最终的产品,可是软件公司总是先弄出来一个不完整的版本,骗大家买了,以后再慢慢“升级”。每次升级都要用户再次付钱。

  2. 编程有多种流派,我喜欢把它们归类成“莫扎特 vs 贝多芬”。当莫扎特开始写乐谱时,作品就已经完成了。他的手稿一气呵成,书法也很好。贝多芬不一样,他总是在怀疑和挣扎。他的作品一般是还没有想好就开始写,然后就往上面贴纸条修改。有一次贝多芬改了9遍才把手稿完成,后来有人把这手稿一层层的撕开,发现第一版和最后一版是一摸一样的。这种改来改去的做法是 Anglo-Saxon 名族的传统,它贯穿了英国式的教育。

  3. 作曲家的工作不是写乐谱,而是构思音乐。最早的时候人们编程都是用汇编语言的,就跟写乐谱差不多。后来他们发明了高级语言,就以为这些语言把编程的问题解决了。但是你仔细一瞧,发现它们只是把编程最微不足道的问题解决了,但是困难的问题仍然困难。这些高级语言与越来越大的野心加在一起,反而让程序员头脑的负担更重了。

  4. 称职的程序员都知道自己头盖骨的尺寸是有限的,所以他们以谦逊的态度来对待工作,像回避瘟疫一样地回避小聪明。

  5. 当我1970年在法国巴黎讲学如何编程的时候很成功,听众都非常积极。回家的路上我又在比利时布鲁塞尔的一个大软件公司进行了同样的演讲,结果非常失败。那恐怕是我一生中最失败的演讲。后来我发现了为什么:他们的管理层不喜欢无懈可击的程序,因为这公司是靠“维护软件”的合同来维持生存的。程序员对此也不感兴趣,因为最让他们兴奋的事情在于不知道自己在干什么。他们觉得如果清楚地知道自己在干什么,那就没有挑战性了,就是无聊的工作。

  6. 研究物理的人如果遇到不理解的事情,总是可以责怪上帝,世界这么复杂不是你的错。但是如果你的程序有问题,那就找不到替罪羊了。0就是0,1就是1,就是你把它搞砸了。

  7. 1969年,在阿波罗号登月之后不久,我在罗马的北约软件工程会议遇到了 Joel Aron,阿波罗计划的软件负责人。我知道每个阿波罗飞船上面的代码都会比前一个多4万行。我不知道“行”对于代码是个什么单位,但4万行肯定是很多了。我很惊讶他们能把这么多代码做对,所以我问 Joel:你们是怎么做到的?他说:做什么?我说:把那么多代码写正确。Joel 说:“正确?!其实在发射前仅仅五天,我从登月器计算轨道的代码里发现一个错误,这代码把月球的重力方向算反了。本来该吸引的,结果写成了排斥。是一个偶然的机会让我发现了这个错误。”我的脸都吓白了,说:这些家伙运气真好?Joel 说:“是的。”

  8. 软件测试可以确定软件里有 bug,但却不可能用来确定它们没有 bug。

  9. 程序的优雅性不是可以或缺的奢侈品,而是决定成功还是失败的一个要素。优雅并不是一个美学的问题,也不是一个时尚品味的问题,优雅能够被翻译成可行的技术。牛津字典对 elegant 的解释是:pleasingly ingenious and simple。如果你的程序真的优雅,那么它就会容易管理。第一是因为它比其它的方案都要短,第二是因为它的组件都可以被换成另外的方案而不会影响其它的部分。很奇怪的是,最优雅的程序往往也是最高效的。

  10. 当没有计算机的时候,编程不是问题。当有了比较弱的计算机时,编程成了中等程度的问题。现在我们有了巨大的计算机,编程就成了巨大的问题。

  11. 我最开头编程的日子跟现在很不一样,因为我是给一个还没有造出来的计算机写程序。造那台机器的人还没有完工,我在同样的时间给它做程序,所以没有办法测试我的代码。于是我发现自己做的东西必须要能放进自己的脑子里。

  12. 我的母亲是一个优秀的数学家。有一次我问她几何难不难,她说一点也不难,只要你用“心”来理解所有的公式。如果你需要超过5行公式,那么你就走错路了。

  13. 为什么这么少的人追求优雅?这就是现实。如果说优雅也有缺点的话,那就是你需要艰巨的工作才能得到它,需要良好的教育才能欣赏它。


十年前的我的来信

backup:

作者:王垠


  十年前的我的来信

今天收到一封 email,反对我在《一种新的操作系统设计》一文中提到的所有想法。让我想起一句话,每一个好的想法都要经受疯狂的反对。很感谢这位读者。他让我想起十年前的那个我。如果十年前那个我来到今天看到这篇文章,恐怕也会发这样的信给现在的我吧。见到年轻的我真好,所以把这封 email 记录在这里。它会鼓舞着我,它让我明白,我能做到很多人想象不到的事情,看到他们看不到的东西。

简单的概述

首先

看了一篇你的<一种新的操作系统设计>的文章!有一些简单的想法!希望可以与你交流一下! 只限于技术性探讨,没有其他意思和目的!言辞不当之处请谅解!同时水平有限有不当之处可以批评!(另外我看了你的Ydiff,如果以后有机会也可以聊聊)

文章是Markdown的,复制到邮件中或许会变形,如果看着不方便可以把原文档发给你!

我不理解你是如何理解"操作系统"这个概念的,也不明白你所谓的超越“Unix 哲学”是什么含义(但是你既然提到了Unix我就暂且认为你想要要的是运行于硬件的操作系统)。 但是我觉得你关于操作系统的理解完全是基于用户层面的.可以看出你是个理想主义者,希望系统按照自己想要的方式做事情!

你所说的11条操作系统的设想,是完全不靠谱的.有的甚至背离的"经典操作系统"的概念的,或者你设想的根本不能算一个操作系统而是架设在操作系统上的一层壳!(就像Hadoop一样是一个分布式'组织系统'),只不过Hadoop只解决了分布式计算(MapReduce)和分布式存储(HDFS),而你想要的更多,但也只是停留在操控层面的,你只是希望屏蔽一些底层的东西,让业务层面的变得更简单,或者看起来更简单(事实上不是每个人的思维方式都和你一样的,有些人认为面向对象的思维方式更自然,而有的人不是,一个完美主义者或者理想主义者总是试图找到一条普世的理论去阐释这个世界,于是有了"弦论",在科学界一是一,二是二的二元论断是非常值得推崇的,但是面对人性,面对需求你或许应该思考更多,爱因斯坦说上帝不玩骰子,然而他最终还是接受(至少是默许)了量子论,bash已经很好用了,却还有人鼓捣出各种各样的shell.)!

关于你文章对操作系统理解的总结:

通信是结构化的 一切都是用"超语言"定义的函数,所有的函数的规范是一元的 一切(系统本身,"函数程序",用户Shell程序)都用超语言实现,超语言不能有指针运算 用"对象数据库"取代关系数据库 不需要文件系统 用户透明与"无限" 为了避免数据移动产生的IO开销,优先自动迁移进程! 标题不好说

你的设计思路对操作系统没有任何现实意义,更多的是空中楼阁,水中月!是没有任何现实基础的"美好瞎想"!

你的文章中只有推翻,而没有建设!你只是说这个不要,那个不要(不要进程,不要文件系统,不要关系数据库...),而没有提供实际的可以取代他们的真正有意义的方案!

你的思维方式不是在设计一种操作系统,而是在设计一种编程语言!

按照你的理论:Python或者Java就是一个完美的操作系统!它几乎满足你要的一切!

超语言(上帝语言)的概念很吸引人,但这绝对是错误的!正如我上面所说人性和需求是复杂的,是动态的,是多变的,哪怕你提供是诸如"英语"一样的通用语言也会有很多人需要添加一个"中文翻译器"!完全不用翻译的意思就是你得要求所有人都遵循和接受你的思维方式!当然或许你会说这种超语言满足一切人的需求,拥有一切易用的特性!好吧,如果真的有上帝语言可以跟任何人沟通,我想还是会有很多人愿意尝试的!

你完全没有理解操作系统是什么,他扮演什么角色具体要处理哪些工作!你所要求的都只是操作系统的外延,而不是操作系统的内涵!你博客的文章标题或许变成<我需要这样一套分布式管理系统>或者<一种新编程语言的设计>更加合适!

就现在计算机的体系结构而言没有指针运算是不现实的,就架构而言现实机器大多是基于寄存器的,讨论基于堆栈的虚拟机对于设计和实现操作系统没有意义,事实上无论那种机型,想要快速随机的访问特定位置的数据间接寻址是一个非常不错的工具,除非你完全抛弃"间接寻址"!或许你在"语法解析"这种逻辑层面不需要这种特性,但系统层面的间接寻址是必须的,除非你设计一套新基于更高理论水平和哲学层次的硬件!

把系统看作为一个"仆人",只要对他下命令他就能按照你想要的方式为你做任何事情(这或许是你的终极目标或者是你目标的一种更为极端的表述)!只想用高级语言的特性而忽略计算机体系结构设想出来的东西根本就不能算作"典型意义上的操作系统"!按照你的方式我完全可以这样设计一个操作系统:只要我告诉他我想做什么,计算机就可以为我做任何事情,比如去厨房做个番茄炒蛋!他就傻乎乎的跑去买番茄和鸡蛋然后...这样的设计岂不是更完美?

我觉得你可能是做"语法分析"的!或许对各种语言的"哲学思想"有独到的见解,但是把这种思想或者更高层次的抽象带到"操作系统"的设计上就是很大职业病!为此你需要推翻现代计算机的体系结构,重新设计和研究可计算理论,不切实际的泛泛而论只会让我看到你的幼稚与任性,露脸与现眼只差一步!

如果你希望你做的是惊世骇俗,前五百年后五百年都不曾有和超越的东西.请先不要将它叫做"操作系统",或者跟"Unix哲学"比较!如果必须这样做,请先搞搞清楚什么事操作系统和Unix哲学!

我的一些相对现实与丑陋(没有那么理想化,很多甚至是迂腐)的看法

我理解的操作系统

最原始的需求:如果将计算机看作一堆冷冰冰的电子元件操作系统的角色就是"驱动,它将这堆冷冰冰的器件合理的组织起来,让他们构成一个系统团结起来工作;要知道程序是直接可以跑在机器上的,不需要任何系统的,但是这意味着你就必须面对这一堆冷冰冰的电子元件了! 我们要的更多:尽管硬件系统变越来越复杂,如果将计算机的计算能力,内存空间,外存空间等看作资源,然而这部分资源终究还是有限的;操作系统的目标是如何更有效的使用和管理这些资源!就因为资源有限所以才需要管理,才需要操作系统,当然你所设想的"无限空间",不需要"文件系统"这种概念完全是背离的! 基于以上两点,现在多数真正的操作系统是面向"硬件"的,如何高效的利用硬件是他们的重点!(宏内核与微内核的争论在这一点上看起来像是对立的,事实上确实是这样么?我觉得,孜孜不倦的挖掘计算机的潜力是每个系统开发者的目标与乐趣所在)

程序,进程与函数

什么是程序什么是进程?去掉进程的概念是不是意味着你需要用别的方法代替?函数吗?事实上他们完全不是一回事儿,进程概念的存在是为了让程序看起来是并行执行的(还是以上这一点,为了更有效的利用CPU资源)!

函数呢? 函数是一种"可计算模型"的表示方法(你完全可以用图灵机,lambda演算,寄存器模型,或者递归来代替,因为他们的本质是一样的)!

你只是用函数描述了计算方法,而进程是有时间考量的,可计算理论中并没有"时间"这个维度!你抛弃了进程,就势必要在函数的定义一个时间维度,在你的观念里函数是一切,它可以做任何事情!现实意义上的计算机更多的是基于寄存器模型和递归模型的,编译器大多数只是将函数表述翻译成寄存器表述或者递归表述,这个过程是一一对应的,他们都是静态的,编译器在这个过程无法给他附上时间维度.编译器不做,操作系统也不做,也就意味着程序员得在代码中加入控制调度的代码,好吧我们回到了最原始的时代了.(当然除非你假设CPU的计算能力是无限的,任何函数都是可以并行执行的,函数的执行是不需要时间的,函数之间的依赖关系是不存在的...就另当别论了)

"“系统调用”,只不过是调用另外一个函数,"对于你的轻蔑傲慢的语气我真的不想吐槽!事实上系统调用还真是调用另外一个函数,对于很多微内核系统虽然其实现是"基于消息"的,但是其外在依然表现为"过程调用"形式,对于被调用资源的实现也依然是个函数! 我不知道你是如何理解函数这个概念的,"任何可计算的问题都能用可计算模型(比如函数)来表示,而可计算模型之外的则是不可计算的",这或许看起来像句废话,但他确实证明你所说的,可计算的一切都可以是函数,但是仅此而已,没有任何外延了,如何安排计算,如何调度计算,可计算理论并没有给出任何有意义的说明;

当然实际问题要复杂的多,除了时间问题,还有你提到的权限问题等!

关于关系数据库与文件系统

系统不需要 SQL,不需要关系式数据库。

我需要强调一点:关系数据库并不仅仅是一个数据存储方案,也是一个数据"计算方案"(很多人用他是不是因为存储方便,事实上它存储不方便也限制多多,诸如数据必须是结构化的,对于树形的或者图形结构的数据还需要扁平化)! 数据存储的方案有很多,你可以直接将数据按一定的格式排版放到一个文件,可以使用键值模型存储简单的数据,或者将数据保存为特定通用格式(比如JSON,XML),或者有很多基于树形结构的文档数据库.基于图论的图形数据库(Neo4j)和狗屎的对象数据,当然也包括基于关系模型的关系数据库!(或许有一天有人会来个大一统,但是谁取代谁的说法显然是不靠谱的),他们各有各的优缺点,而关系数据库更是基于严谨成熟的关系数据理论构建的,他的数据结构简单,运算简介高效,不明白为什么有人会讨厌SQL,事实上他是最简洁方便直观的工具,他隐藏了很多计算细节,甚至你只需要告诉他我需要什么(而不是如何做),他就能很好的为你提供服务!

如果一切都是对象,随意的构造数据,存取无疑是最方便的),但构建在对象之上的算法就必须自己实现(这将会是灾难),相比于自己在对象之上实现算法,"构造结构化数据"显然更简单(或者机械化),基于成熟的关系数据理论也可以让你避免很多错误!我想这也是关系数据库占统治地位的主要原因!

对于文件系统,理解有很多种,基于磁盘的文件系统和构建于文件系统之上的"文件系统"!操作系统意义上的是前者,而后者大多数是是一些"虚拟文件系统",网络文件系统,或者分布式文件系统!后者更接近于"文件管理系统",他没有解决数据如何存储在物理介质上的问题,主要面向业务,提供"文件系统透明"这一概念!操作系统设计提出"不要文件系统"和"金三胖不要姑父"一样荒唐!

解码是必须的

解码(解析)是一个"理解数据"的过程!

你可以把任何数据看作一个"有特定语意的对象",作为人很容易凭直觉和经验认定12345是数字,abcde是字母!但对于计算机他只是一块放在特定位置的"没有特定意义"的"数据",我们使用数据就必须对其赋予一定的含义,知道他是什么,如何组织!计算机不会下意识的知道12345是数字,而abcde是字母!理解数据必须存在,哪怕是一个结构化的数据,要使用它你就必须理解他,同时要让计算机理解他!(事实上你在判断12345是数字之前已经对他做了解码了)

所以我的结论是:解码是必须的!不是所有事情都是理所应当的, 或许向你这样的人思维速度非常快,有些问题你凭直觉和经验就得出了结论!以至于你甚至意识不到你对问题做出了思考!但是理性是必然存在的!

那么这个问题就变成了"谁来解码"!

目前而言可以有下面几个选择:

计算机自己(硬件系统和操作系统)

事实上计算机有一定的解析数据的能力 就冯诺依曼体系结构的计算机而言,它要求程序按照特定的指令系统被编码存放,这种规范的是一个有限的集合!无限延伸让他处理任何的数据是不可能的(比如你给计算机一个Torrent文件他或许只是个文本,但让计算机知道接下来要做什么是不可能的,不可能任何系统都安装了这个解码器,因为不是所有人都需要的,你必须许更具特定的需求自己安装Bencode/Bdecode)!更高层次的解析(理解)需要具体问题具体处理,除非你颠覆现有的体系结构重新设计基于更高理论水平和哲学层次的可计算模型. 把所有的东西交给系统来处是不切实际且没有必要的(如果特定场景或许可以),所以你或许应该把这些事情交给下面的选项来做!

编译器(或者解释器) 当我们编译一个C的结构体的时候,编译器提供了编码和解码,它根据语法定义的数据的宽度得到特定偏移,将数据按照特定偏移排布在特定的位置这是一个编码的过程,计算机根据自己的指令系统的定义和规范对编码的数据进行加载和运算,这是一个解码的过程!从函数式编译到寄存器模型亦是一个翻译的过程,这个翻译过程为了让不同系统之间相互交流编码和解码是不可避免的!

程序库

我们很容易的使用已有的库去解析JSON,XML,让他们变成你所谓的对象,应为你或许觉得在用户层面上使用对象的概念会更简单!

用户(程序员): 对前无古人的个性化数据赋予一定的语意,用户必须制定特定的格式或者协议,然后手动编写相应的代码实现编码与解析!然而这是大多数创造力的来源!如果你做创造性的工作,我想这会是大多数情况!

关于如何解决分布式问题

你提到的移动"计算"优于"移动数据",这在大多数情况下是正确,包括Hadoop这种系统也是那么做的,这并无新意!

然而事实上分布式问题的核心在于调度,在于如何抽象成一个分布式计算模型来一劳永逸的解决任何可分布式计算的问题,在这里还要明确一点有很多问题是不可分布式计算的,就是因为存在这种问题,构建一劳永逸的模型就几乎成为不可能的至少是有代价的事情,MapReduce或许是一个很不错的模型,但在特定的情景下依然会显得力不从心,同时无可避免的引入了无关代码去分解问题(只是将这个过程模式化了),很多情况下特定的业务逻辑下,这种方案并不是最高效的.

而Java和其他一些分布式方案并不是真正意义上的"分布式模型",他并没有解决任何"问题分解"和"调度"的问题,程序员仍然需要根据自己的业务需求分解简化问题,决定哪些问题在哪些节点运行,何时运行!

不需要显式的使用特定的方法就能让系统跟安排进程执行一样自动的分布这些计算和数据到不同的节点的通用系统我没见过(或许还真有)!


程序员的心理疾病

backup:

作者:王垠

  程序员的心理疾病

由于程序员工作的性质,他们长期以来受到的所谓“黑客”式的“熏陶”,形成了一种行业性的心理疾病。这里我就简单的把我所观察到的一些症状总结一下。

无自知之明 

由于程序员的工作最近几年比较容易找,工资还不错,所以很多程序员往往只看到自己的肚脐眼,看不到自己在整个社会里的位置其实并不是那么的关键和重要。很多程序员除了自己会的那点东西,几乎对其它领域和事情完全不感兴趣,看不起其他人。这就是为什么我的前同事 TJ 作为一个资深的天体物理学家,在一个软件公司里面那么卑微。貌似会写点 node.js,iOS 软件的人都可以对他趾高气昂的样子,而其实这些东西的价值哪里可能跟 TJ 知道的物理知识相提并论。很多科学家其实都 可以轻而易举的掌握程序员知道的东西,有人却认定了他们不是这个专业的,不懂我们的东西,或者故意把问题搞复杂,让他们弄不明白。让人感觉是在阴沟里翻了船被老鼠欺负。

如果力学工程师犯了错误,飞机会坠毁;如果结构工程师犯了错误,大桥会垮塌;可是如果软件工程师犯了错误,大不了网站挂掉一小时,重启一下貌似又好了。所以所谓“软件工程师”,由于门槛太低,他们的工作严谨程度,其实是根本没法和力学工程,结构工程等真正的工程师相提并论的。实际上“软件工程”这个名词根本就是扯淡的,软件工程师也根本不能被叫做“工程师”。跟其他的工程不一样,软件工程并不是建立在科学的基础上的,计算机科学也根本不是科学。

垃圾当宝贝 

按照 Dijkstra 的说法,“软件工程”是穷途末路的领域,因为它的目标是:如果我不会写程序的话,怎么样才能写出程序?

为了达到这个愚蠢的目的,很多人开始兜售各种像减肥药一样的东西。面向对象方法,软件“重用”,设计模式,关系式数据库,NoSQL,大数据…… 没完没了。只要是有钱人发布的东西,神马垃圾都能被吹捧上天。Facebook 给 PHP 做了个编译器,可以编译成 C++,还做了个 VM,多么了不起啊!其实那种东西就是我们在 Indiana 第一堂课就写过的,只不过我们是把比 PHP 好很多的语言翻译成 C。我们根本不想给 PHP 那么垃圾的语言做什么编译器,让垃圾继续存活下去并不能证明我们的价值。

其实软件里面有少数永恒的珍宝,可惜很少有人理解和尊重它们的价值。这在其它的工程领域看来是不可思议的,然而这却是事实。由于没有科学作为理论的基础,没有实验作为检验它们的标准,软件行业的很多东西就像现代艺术一样,丑陋无比的垃圾还能摆在外表堂皇的“现代艺术博物馆”里面,被人当成传世大作一样膜拜。

为了凸显自己根本不存在的价值,又提出一些新的“理念”,就像有些现代艺术家一样,说“艺术的目的不是为了美,而是为了自由。”哦,这就是为什么你们可以自由地把那些让人反胃的东西放在博物馆里,还要买门票才能参观?

宗教斗争 

当然了因为没有实质的技术,为了争夺市场和利益,各种软件的理念就开始互相倾轧。一会儿说软件危机啦,面向对象方法来拯救你们!一会儿又提出设计模式。过了一会儿又有人说这些设计模式里面有些模式是“反模式”,然后又有人把函数式编程包装起来,说是面向对象编程的克星,一会儿是关系式数据库,一会儿是 NoSQL,一会儿是 web,一会儿是 cloud,一会儿又是 mobile…… 每个东西都喜欢把自己说成是未来的希望。

这就是为什么有人说在软件行业里需要不停地“学习”,因为不断地有人为了制造新的理念而制造新的理念。在这样一个行业里,你会很难找到一个只把程序语言或者技术当成是工具的人。如果有人问你对某个语言或者技术的评价,是非常尴尬甚至危险的事情,所以最可靠的办法就是不做评论,什么都不要说。

引难为豪 

在 IT 行业里批评一个技术难用,是一件非常容易伤自尊的事情,因为立马会有人噼里啪啦打出一些稀奇古怪的命令或者一大篇代码,说:就是这么简单!然后你就发现,这些人完全不明白什么叫做设计,他们以自己能用最快的速度绕过各种前人的设计失误为豪,很多程序员甚至以自己打字快为豪。

当遇到这样的人,我的经验是,千万不要恭维他们。你必须大声地嘲笑这些东西的设计,并且指出它们的失误之处,否则你不但助长了这些人的气焰,而且将来自己的自尊也难保了。很可惜的是不是每个人都有这种勇气把这些话说出来,这就造成了今天的局面,纷繁复杂的垃圾充斥着世界。爱因斯坦说,你需要很多的天才和非常大的勇气,才能追求到简单。

非常大的勇气…… 也许就是这个意思。

去读文档! 

不知从什么时候开始,人们开始引用 Eric Raymond 的一篇叫做《提问的艺术》的文章,这篇文章后来就成为了对提问者没礼貌的借口。由于这篇文章的误导,当你希望同事能给你一个手把手的演示的时候,他们往往会丢给你一篇不知道什么时候写的文档,让你自己去读,仿佛文档就可以代替人之间的直接互动。况且不说这文档可能已经过时,里面有很多地方已经不符合最新的设计,而这意味着在潜意识里,他们觉得高你一等。他们甚至会对你说,如果每个新人来了我们都花这么多时间去指导他们入门,哪里还有时间干正事呢?然后你就意识到了,你在他们心里的地位,其实是如此的卑微和低下。

有的人稍微委婉一点,当你提问的时候,他们会二话不说打开一个浏览器窗口,在里面用 Google 搜索,然后指给你:看,就是这样。貌似比较礼貌,但那其实意味着他们在教训你:Google 一下就找到了的,自己不动脑筋!有谁不会用 Google 呢?提问的人恐怕是想得到 Google 不能给他的答案。真正有礼貌的人在不知道答案的时候是不会当面去帮你搜索的,他会对你说:“这个我也不知道…… 要不你搜索一下?”

在 IRC 的聊天室里,由于隔着网络的屏障,这种对提问者没礼貌的现象就更加嚣张。我曾经有几次去 Java 的聊天室问一些貌似基础,而其实很深入的语言设计问题,结果没有一次不是以收到像“去读 API!”这样的回答而结束。API 谁不会读,然而我需要的是一个有血有肉的人对此的理解。所以后来我根本不去 IRC 这种地方了,因为那里面对你打字的基本上已经不是人类了。他们觉得你问问题浪费了他们的时间,好像他们一天到晚泡在 IRC 里面就是在做什么正事似的。不想回答问题,不开口还不行吗。后来你发现,原来在 IRC 里面训斥新手就是这些人唯一的乐趣,所以其实他们是非开口说话不可的。然而这次他们遇到的却不是个新手,而是一个可以把 Java 整个造出来的人。

像 Haskell 之类的聊天室貌似稍微友好一点,然而后来你发现他们显得友好是有所企图的。因为当时 Haskell 还没有很多人用,他们需要吸引新手,所以竭尽所能的诱导他们。而一旦它用户稍微多了一点,有声势了,那些积极分子就成了专家一样的人物。他们就开始写书,然后就开始牛气哄哄的了。然后你就会发现当对 Haskell 的设计提出异议的时候,这些“id”们是多么的不友好,有理也说不清。所以最后你发现,其实所有语言的所谓“社区”都一个德行。如果 Haskell 有一天像 Java 一样如日中天(当然不大可能),肯定对大部分问题的答案也就是“去读API!”其实它已经在向这一步发展了。

不得不指出,《提问的艺术》等介绍“黑客文化”的文章对于这种现象的出现有着极大的责任。说穿了,写这些文章的人一般都是 Unix 的跟屁虫。这种文章试图抹去人类文明几千年来传承的文化,而重新给“礼貌”做出定义。其结果是,人类的文明因为这些文章,在程序员的世界里倒退了几十甚至几百年。很多外行人人不喜欢跟程序员说话,叫他们是 nerd,就是这个原因。

不要提问,不要谦虚,不要恭维 

跟上面的症状相似,程序员世界里的一条重要的潜规则是:只有菜鸟才会问问题。所以如果你有任何机会可以自己得到答案,就不要试图向人“请教”,尤其不要显得好奇,否则你就会被认为是菜鸟。我有几次不耻下问的经历,最后导致了我被人当成菜鸟。我只是觉得那问题有趣,也许能够启发我设计自己的东西,所以吃饭时觉得是个话题可以说一下,结果呢就有人忙着鄙视你,那么小的问题都没搞清楚。正确的态度应该是诚实,直接,见惯不惊,那有什么大不了的,我什么没见过,我很怀疑。

随之而来的引论就是:不要谦虚!那些“职场经验”之类的文章告诉你的进入新的公司工作,要谦虚好问,对 IT 公司这种不讲美德的地方是不管用的。有的大 IT 公司有所谓的“文化”,比如叫你要“Googley”,要“humble”,其实只是用来贬低你价值的借口。他们要你向他们“学习”,但其实他们没有什么值得学习的地方。他们只是想让你安于“本分”,做一些微不足道,不能发挥你才能的工作。看看那些叫你要 humble 的人,他们 humble 吗?所以跟江湖一样,在 IT 公司里面一件很重要的事情是,亮出自己的宝剑和绝招,给人下马威。介绍自己的东西一定要自豪,这就是世界上最好的,无敌的,没有其他人能做到!不能有任何保留。不要像科学家一样介绍自己技术的局限性,否则随之而来的就是有些人对你价值的怀疑和对你自信心的打击。

另外要注意的是对于别人介绍的东西,不要轻易地表扬或者点头,否则有人就更有气势了。你要问这样的问题:这里面有什么新的东西吗?这个事情,另外一种技术早就能做了啊,没觉得有什么了不起。

哎,总之这样还是很累,所以最好是能不跟程序员讲话就不讲。

以语言取人 

你的软件是什么语言写的,告诉别人的时候是千万要小心的,不到万不得已最好不要说。因为十有八九,对方会立即在心里对你的软件的价值做出判断,光凭你用的是什么语言。

很多程序员都以自己会用最近流行的一些新语言为豪,以为有了它们自己就成了更好的程序员。他们看不到,用新的语言并不能让他们成为更好的程序员。其实最厉害的程序员无论用什么语言都能写出很好的代码。在他们的头脑里其实只有一种很简单的语言,他们首先用这种语言把问题建模出来,然后根据实际需要“翻译”成最后的代码。这种在头脑里的建模过程的价值,是很难用他最后用语言的优劣来衡量的。有时候高明的程序员用一个语言并不是因为他只会用那种语言,而是其他的原因。他们的头脑里有着万变不离其宗的理念,可以让他们立即掌握几乎任何语言或者工具,所以他们对所谓的“新语言”都不以为然。可是很多人误以为他们不愿意学习“新东西”,从而从心里鄙视他们。其实计算机的世界里哪里有很多新的东西,只不过是有人给同样的东西起了很多不同的名字而已。如果连这样的程序员都不能理解你的技术,就说明你的技术设计有问题,而不是他们有问题。就像 Seymour Cray 说的,我只能理解简单的东西,如果它太复杂了,我是不能理解的。

早些年的时候,大家都认为招募某种特定语言的程序员是一种浮浅的做法,很多公司看重的都是解决问题的能力。可是近些年我发现这些浮浅的做法越来越普遍。可以说现在像 Google 这样的公司面试员工的方式和态度,其实还不如八年前我的第一份国内工作。很可笑的是,我离开 Coverity 之后那段时间面试的所有声称使用 Python 的公司,最后都认定了我是 Python 的菜鸟。然而如果你知道 PySonar 的技术含量就会明白,这样的东西需要水平高过 Python 的创造者 Guido van Rossum 很多的人才能造出来。在制造了 PySonar 之后,他对程序语言的理解,他的每一个错误都被我看得清清楚楚。当然,Ruby 就更烂了,我可以说,Matz 这人其实根本不知道他在干什么。

说到这些的时候,我很惊讶的发现有人来信告诉我,还是等你做出了什么“成就”再来说这些话吧。从这里我看到了“竞争”和“攀比”的思想在有些人心里是多么的根深蒂固,我也看出了这些“大牛”在他们心里是个什么地位。然而他们是激将不到我的,因为我根本没有跟别人“比”的意思。说实话吧,就算你打死我,我也做不出有那么多毛病的语言来。我两个小时之内设计个语言都比 Python, Ruby, JavaScript 要好很多。我不可能以“超过 Python 和 Ruby”这么肤浅的目的为动机,来达到别人所认同的“成就”。打个比方,我有什么必要证明我比 Justin Bieber 或者 Lady Gaga 强呢?我根本不明白这些人到底有什么成就,也完全没有必要向他们的粉丝证明我的价值。在这几次有伤自尊的面试之后,我再也不会给任何使用 Python 作为主要语言的公司工作。

跟屁虫 

有些程序员对新手和同事是那么的不友好,然而对大牛们拍马屁的功夫可真是出类拔萃。我刚到旧金山的几个月有时候参加一些程序语言的“meetup”,后来我发现这种 meetup 都是宗教气氛非常浓厚的地方,跟传销大会差不多。Scala 的 meetup 里面的人几乎全都对 Scala 和 Martin Odersky 顶礼膜拜,甚至把 Rod Johnson 请来说一堆胡话。Clojure 的,当然基本上把 Rich Hickey 当成神,甚至称他为“二十一世纪最重要的思想家之一”。各种 talk 总是宣扬,哇,我们用 Scala/Clojure 做出了多么了不起的东西云云,其实只不过是在向你兜售减肥药。

很多人喜欢做这些新的语言和技术的“evangelist”,尽显各种马屁神功,然后就开始写书,写 blog,…… 目的就是成为这个“领域”的第一批专家。这就难怪了,再垃圾的语言也有一大批人来鼓吹。因为这些没真本事的人,随便把一个东西捧上天都有自己的好处。

由于受到这些“先知”的影响,有些人开始在他们自己的公司里“布道”。比如有人在 Python 的 meetup 集会时告诉我,他试图在自己的小组里推 Python,可是一些老顽固一定要用 Java,认为 Java 才是王道。很鄙夷不高兴的样子。我并不认为 Java 是很好的语言,然而 Python 也好不到哪去。它们在我眼里只不过是临时拿来用一下的工具,可是我仍然能用它们写出一流的代码。

看到这些宗教性质的聚会,我终于理解了一些地区是如何被从一个国家分裂出去,最后沦落为另外一个国家殖民地的。最早的时候,一般是派传教士过去“传经”,然后就煽动一小部分人起来造反。到后来就可以名正言顺的以“保护传教士”,“保护宗教自由”,“维持和平”等理由把军舰开到别人家门口……


创造力的真正含义

backup:

作者:王垠


  创造力的真正含义

拥有创造力,意味着别人都在看球赛的时候,你独自在操场上练球,欣赏那球飞出去时的弧线。

拥有创造力,意味着让你最开心的事情不再是享受别人的创造,而是创造。

拥有创造力,意味着你会从非常不起眼的小东西里面得到启发,而当你兴高采烈的告诉其它人的时候,会遭遇到他们司通见惯的语气。

拥有创造力,意味着你不再能从本领域专家的嘴里得到启发。你会更喜欢跟完完全全的外行讲话。你会把世界上最难的一些问题编成小故事讲给你可爱的女朋友,而她的回答,经常莫名其妙撞上你梦寐以求的答案。

拥有创造力,意味着你会在所有的东西身上看到可以改进的地方。你会怀疑设计这些东西的人其实根本没用过他们自己的产品。

拥有创造力,意味着你会永远像一个小孩。你会看到所谓的“大人”们看不到的可能性,这些“大人”有可能比你还要小几十岁。当你告诉他们自己的想法时,他们的反应总是让你失望。在父母的眼里,你总是不能成熟,而在你的眼里,父母和其他人一样,看不到其实他们自己才是真正不成熟的人。

拥有创造力,意味着你人生中遇到的最大障碍不再是技术的难题,而是人类的愚蠢。你人生最大的错误,是低估了这种愚蠢的力量。

拥有创造力,意味着你会非常孤独。别人推崇至极的东西在你眼里不过是小菜一碟,所以人们会认为你不是他们的同类,而优先与同样的狂热分子为伍。你有时甚至会发现自己没有逃避的自由,没有不跟着起哄的自由。

拥有创造力,意味着你经常会为了得到最底层的启发,问一些貌似很基础的问题。有些人看到这些问题就会以此作为你水平不够的证据,从而以为可以凌驾于你之上。如果是在 IRC 聊天室,他们会说:“去,读了文档再来问!”

拥有创造力,意味着你有比别人大很多的安全感,你不会理解,上司或者导师为什么会害怕你不能完成项目,因为他们永远不会看到,也不会相信你能看到的东西。你会需要反反复复的安慰他们,但他们仍然会像拿到新衣服之前的皇帝一样派人来打探你,看你是不是真的在制造传说中那能够鉴别 IQ 的布料。

拥有创造力,意味着你不会再在乎人们不知所以的赞许。大部分时候这种赞许反而变成了对你能力的侮辱,所以你多希望他们什么都别说,特别是不要当着众人的面,因为你知道,这除了引起其他人的嫉妒和敌意,没有任何其它作用。你会想在地上找个缝钻进去。

拥有创造力,意味着你自认为的一些雕虫小技会被人当成是大作,而自己真正满意的大作却由于看起来小,没有人理会。每当你做出一点什么,人们就以为你是什么,从而把你的一生定格在那里。他们不明白,你的价值不在于你做的东西,而在于你自己。你是没有界限的人。

拥有创造力,意味着你会分不清什么是新的想法,什么是旧的想法。因为不管别人看起来新的还是旧的,都是你自己想出来的。因为你忙着创造,你没有时间去追究一个想法别人是否已经有了。你只知道什么是好的,管它是新的还是已经有的。你知道自己可能是在重新发明轮子,但是你知道,当把轮子全部都发明完了之后,除了发明新的东西你别无选择。你会发现,发明轮子是非常重要的练习,因为没有发明过轮子的人,他们也发明不出什么特别好的车子。

拥有创造力,意味着你会很难找到工作,因为面试你的人会提出很多需要死记硬背的问题。面对他们的时候,你根本不知道那些术语是什么,然而等你回头一查,发现它们是自己几年前想出来却又抛弃了的,没有名字的主意。

所以,拥有创造力带来的更多是苦难和孤独。可是如果上天再给你一次可以抛弃它的机会,你仍然会毫不犹豫的说,不!


程序语言与它们的工具

backup:

 作者:王垠


程序语言与它们的工具

谈论了这么多程序语言的事情,说得好像语言的好坏就是选择它们的决定性因素。然而我一直没有提到的一个问题是,“程序语言”和“程序语言工具”的设计,其实完全是两码事。一个优秀的程序语言,有可能由于设计者的忽视或者时间短缺,没有提供良好的辅助工具。而一个不怎么好的程序语言,由于用的人多了,往往就会有人花大力气给它设计工具,结果大大的提高了易用性和程序员的生产力。我曾经提到,程序语言其实不是工具,它们是像木头,钉子,胶水一样的材料。如果有公司做出非常好的胶水,粘性极强,但它的包装不好,一打开就到处乱跑,弄得一团糟。你是愿意买这样的胶水还是稍微差一点但粘性足够,包装设计合理,容易涂抹,容易存储的呢?我想大部分人会选择后者,除非后者的粘性实在太弱,那样的话包装再好都白搭。

这就是为什么虽然我这么欣赏 Scheme,却没有用 Scheme 或者 Racket 来构造 PySonar 和 RubySonar,甚至没有选择 Scala 和 Clojure,而是“臭名昭著”的 Java。这不只是因为 PySonar 最初的代码由于项目原因是用 Java 写的,而且因为 Java 正好有足够的表达能力,可以实现这样的系统,但是最重要的其实是,Java 的工具非常成熟和迅捷。很难想象如果缺少了 Eclipse 我还能在三个月内做出像 PySonar 那样的东西。而现在我只用了一个月就做出了 RubySonar,其中很大的功劳在于 IntelliJ。这些 IDE 的跳转功能,让我可以在代码中自由穿梭。而它们的 refactor 功能,让我不必再为变量的命名而烦恼,因为只要临时起个不重复的名字就行,以后改起来小菜一碟。另外我还经常使用这些 IDE 里面的 debugger,利用它们我可以很方便的找到 bug 的起因。PySonar2 在有一段时间变得很慢,看不出是哪里出了问题。最后我下载了一个 JProfiler 试用版,很快就发现了问题的所在。如果这问题出现在 Scheme 代码里面,恐怕就要费很多功夫才能找到,因为 Scheme 没有像 JProfiler 那样的工具。

但这并不等于说学习 Scheme 是没有用处的。恰恰相反,Scheme 的知识在任何时候都是非常有用的。一个只学过 Java 的程序员基本上是不可能写出我那样的 Java 代码的。虽然那看起来是 Java,但是其实 Scheme 的灵魂已经融入到其中了。我从 Scheme 学到的知识不但让我知道 Java 可以怎么用,而且让我知道 Java 本身是如何被造出来的。我知道 Java 哪些地方是好的,哪些地方是不好的,从而能够择其善而避其不善。我的代码没有用任何的“Java 设计模式”,也没有转弯抹角的重载。

其实我有空的时候在设计和实现自己的语言(由于缺乏想象力,暂命名为 Yin),它的实现语言也在最近换成了 Java。Yin 的语法接近于 Scheme,好像理所当然应该用 Scheme 或者 Racket 来实现。有些人可能已经看到了我 GitHub 上面的第一个 prototype 实现(项目已经进入私密状态)用的是 Typed Racket。Racket 在很大程度上是比 Java 好的语言,然而它却有一个让我非常恼火的问题,以至于最后我怀疑自己能否用它顺利实现自己的语言。

这个问题就是,当运行出现错误的时候,Racket 不告诉我出错代码的具体行号,甚至出错的原因都不说清楚。我经常看到这样一些出错信息:

“函数调用参数个数错误”“变量 a 没有定义,位于 loop 处” 

只说是函数调用,函数叫什么名字不说。只说是 loop,文件里那么多 loop,到底是哪一个不知道。出错信息里面往往有很多别的垃圾信息,把你指向 Racket 系统里面的某一个文件。有时候把代码拷贝进 DrRacket 才能找到位置,可是很多时候甚至 DrRacket 都不行。每当遇到这些就让我思路被打断很长时间,导致代码质量的下降。

其它的 Scheme 实现也有类似的问题,像 Petite Chez 这样的就更加严重,只有商业版的 Chez Scheme 会好一些,所以这里不只是小小的批评一下。这种对工具设计的不在意心理,在 Lisp 和 Scheme 等函数式语言的社区里非常普遍。每当有人抱怨它们出错信息混乱,没有 debugger,没有基本的静态检查,铁杆 Schemer 们就会鄙视你说:“Aziz 说得好,我从来不 debug,因为我从来不写 bug。”“函数式语言编程跟普通语言不一样。你要先把小块的代码调试好了,问题都找到了,再组合起来。”“当程序有问题却找不到在哪里的时候,说明我思路混乱,我就把它重写一遍……”我很无语,天才就是这样被传说出来的 :)

除了由于高傲,Scheme 不提供出错位置的另外一个重要原因,其实是因为它的宏系统。由于 Scheme 的核心非常小,被设计为可以扩展成各种不同的语言,所以绝大部分的代码其实是由宏展开而成的。而由于 Scheme 的宏可以包含非常复杂的代码变换(比 C 语言的宏要强大许多),如果被展开的代码出了问题,是很难回溯找到程序员自己写的那块代码的。即使找到了也很难说清楚那块代码本来是什么东西,因为编译器看到的只是经过宏展开后的代码。如果实现者为了图简单没有把原来的位置信息存起来,那就完全没有办法找到了。这问题有点像有些 C++ 编译器给模板代码的出错信息。

所以出现这样的问题,不仅仅是语言设计者的心态问题,而且是语言自己的设计问题。我觉得 Lisp 的宏系统其实是一个多余的东西,带来的麻烦多于好处。一个语言应该是拿来用的,而不是拿来扩展的。如果连最基本的报错信息都因此不能准确定位,扩展能力再强又有什么意义呢?所以强调一个语言可以扩展甚至变成另外一种语言,其实是过度抽象。一个设计良好的语言应该基本上不需要宏系统,所以 Yin 语言的语法虽然像 Lisp,但我不会提供任何宏的能力。而且由于以上的经历,Yin 语言从一开头就为方便工具的设计做出了努力。


RubySonar:一个 Ruby 静态分析器

backup:

作者:王垠


RubySonar:一个 Ruby 静态分析器

在过去一个多月时间里,我大部分时间都在做一个 Ruby 的静态分析叫做 RubySonar。它使用与 PySonar2 类似的技术,不过针对 Ruby 的语义进行了很多调整。现在这个分析器已经能够支持 Sourcegraph 的 Ruby 代码搜索和浏览。这比起之前的效果是一个很大的进步。

在 RubySonar 的帮助下,对于很多 repo,Sourcegraph 可以搜索到比以前多几十倍甚至上百倍的符号,当然代码的使用范例也随之增加了。代码定位的准确性有很大提高,基本不会出现错位的情况了,另外还支持了局部变量的加亮,所以看起来有点像个“静态 IDE”的味道。

由于 RubySonar 比起 Sourcegraph 之前用的基于 YARD 的分析在速度上有上百倍的提高,我们现在可以处理整个 Ruby 标准库(而不只是以前的一小部分)。Ruby on Rails 的结果也有比较大的改善。另外,以前不支持的像 Homebrew 之类的独立应用,现在也可以分析了。

RubySonar 的静态分析使用跟 PySonar2 相同的跨过程,数据流+控制流分析,而且采用同样的类型推导系统,所以分析的精度是很高的。我还没有跟 Ruby 的 IDE 比较过,不过因为构架的先进性,它应该已经能处理一些现在最好的 Ruby IDE 也搞不定的事情,当然由于时间短,在细节上比起它们肯定也有不足之处。

虽然 Ruby 和 Python 看起来是差不多的语言,为了把 PySonar2 改到 Ruby 上,还是做了不少的工作的。最开头我试图让它们“重用”大部分代码,只是在不一样的地方做一些条件分支进行特殊处理。可是后来发现这样越来越复杂,越来越危险。为了照顾一个语言的特性,很容易破坏掉为另一个语言已经千辛万苦调试好的代码。结果最后决定把它们完全分开,其中共享的代码通过手工拷贝修改。事实证明这个决定是正确的,否则到现在我可能还在为一些莫名其妙的错误伤脑筋。这个经验告诉我,所谓的 DRY(Don't Repeat Yourself)原则其实有它的局限性。有时候你真的是宁愿拷贝粘贴代码也不要共享。

当然到现在,我对 Ruby 和 Python 之间的差别也就有了很清楚的对比。它们的一些灵活的设计给了我一定的启发。我看到了过于死板的静态类型系统带来的一些没必要存在的不便,然而我也清楚地看到它们过度的灵活性和一些不知所以的设计给程序员和静态分析带来了哪些不必要的麻烦。所以虽然 PySonar 和 RubySonar 都可以说是针对这两种语言最先进的静态分析技术,但它们有一些不可逾越的局限性。它们能够发现程序里存在类型错误,但它们却不能保证程序完全没有类型错误。我并不认为 PySonar 和 RubySonar 是我最好的作品,我只是顺手拈来,尽力而为,另外从它们的设计中汲取一些经验教训,让我自己设计的语言避免这些问题,却又相对灵活。

目前 RubySonar 还缺少对 native 库代码的支持,但是由于代码始终保持了简单的原则(RubySonar 只有 7000 多行代码),那些东西会比较容易加进去。感兴趣的 Ruby 用户可以看看自己的 repo 是否已经得到处理,如果没有的话可以来信告诉我,也欢迎给我指出其中存在的问题。


程序语言与……

backup:

  程序语言与……

程序语言的设计类似于其它很多东西的设计。有些微妙的地方只有用过更好的设计的人才能明白。现在我就简要介绍一下我自己的体会。

程序语言与微波炉 

有的程序语言就像左边的,现在中国市场上流行的微波炉。布满了花哨的一年都用不到一次的专用菜单,却连最基本的 0-9 数字键都没有。输入个时间都要费脑筋组合一下,按键位置不顺手,不能一次按到位,而且还不能达到需要的精度。

有的程序语言就像右边的,美国市场上常见的微波炉,几十年不变的设计。虽然按键很少,但十个数字键总是少不了,而且采用标准的“电话键盘”排列。十个数字能够组合产生出任意的时间,所以不管是在自己家里,别人家里,公司或者学校,你总是可以按照自己的经验,食物包装或者菜谱上的说明,迅速而精确的输入想要的时间。

可惜的是,在中国你已经买不到这么简单实惠的微波炉了。我们中国人学会了美国的很多糟粕,却没有把这么简单,这么好的设计思想学过去。

中国的微波炉厂商之所以放上这么多的花样,是因为商家抓住了中国人的贪便宜心理。看,一个微波炉可以煮米饭,烤肉串,还可以蒸排骨,那其他的厨具都可以不用买啦!可惜因为所以,科学道理,微波就是微波。加热牛奶剩饭之类的事它做得很好,可是要做美味佳肴它就不行了。煮米饭不如电饭煲,烤肉串不如烧烤架,蒸排骨不如蒸锅,炖东西不如砂锅…… 美国人和稍微有点经验的中国人早就知道这个道理,所以从来不期望微波炉能做超越它所擅长的事情。

虽然美国人在这些硬件上非常精明,可是在软件上还没发展到那种地步,很多时候对一些不可救药的软件技术寄予太多的希望。左边的微波炉就好像某些程序语言,本来当初设计就是给标准没那么高的人用来处理很简单的网页的。可是后来有人忽然想让它成为一个“万能语言”,用来做复杂的,对性能和可靠性都很高的服务器程序甚至机器人控制程序。然后你就发现类似微波炉的问题,因为一些不可逾越的设计差别决定了它是不可能把那些事情做好的,而且对有些应用还有严重的安全隐患。当然你可以缓慢的“改进”这语言,让它慢慢的提高做这些事的水平。可是这种改进的终点也许只是另一种早已存在的语言。而且由于不想破坏已有的代码和特性,所以每一步的改进都异常艰难。这种方式远远不如直接针对需要选择不同的语言,或者设计新的语言来的迅速和有效。

程序语言与减肥 

很多人都想减肥,就像很多人都想学会编程。姑且不说一味的减肥好不好,现在只谈一下什么是有效的减肥方法。

我自己也有一段时间很胖,也有减肥的经历,而且非常成功。如果有一天我不小心又变胖了,我有非常科学而可靠的办法减回去。我的方法就是一句话:让每天吃进去的热量比消耗的少一些,但是不至于难受,另外适当运动来增加热量的消耗。很显然嘛,根据热力学定律,每天消耗的能量比摄入的多,多出来的部分只能通过分解你身上的物质(脂肪)来产生。我的减肥方法就像某些程序语言教会我的编程理念,是不随潮流而改变的真理。它让我的程序不管用什么语言写都优美而精悍。

我不是自私的人,我希望大家都健康一点,养眼一点。我已经轻易地告诉了你减肥的终极真理,一分钱都不收,可是你不相信我。你觉得肯定没那么简单,或者你觉得那样太辛苦,自己不可能照办。这就像很多人对编程的希望:要是我不学编程也能编程该多好啊!

很多程序语言就是针对这群人而产生的,它们大部分的工作花在了研究人的心理和做广告上面。它们就像电视广告里铺天盖地的减肥药:不需运动,不用节食,一个星期瘦 20 斤!它们提出各种新的术语,什么减肥茶,片,胶囊,螺旋,燃脂,纤维,宫廷,祖传,秘方,各种生化术语…… 再加上一些 PS 出来的前后效果对比图,你痛快地花不菲的价钱买了这药,然后每天好几次的像做化学实验一样精确的按时按量服用。这时候任何人跟你说这药不灵的话你都不会相信,你觉得这些人都是想跟你争夺异性的目光故意想让你继续胖下去而其实她(他)们自己背地里也吃这药,所以你对此减肥药必胜的信心有增无减。

当然你不会成功。在持续服用好多个月,甚至好几年之后,你按照广告里说的“无效退款”条例要求退款。可是减肥药公司说,是你自己没有按说明书服用,或者你吃药之前肯定比现在还胖很多。你拿不出证据,后悔当初没到公证处开你当时体重的证明。可是你仍然相信,世界上一定会有真正有效的减肥药。你觉得国内的公司喜欢骗人,所以你到了美国,寻找传说中那世界一流的减肥药……

程序语言与棋 

有人说好的程序语言就像国际象棋(chess),在了解简单的规则之后,你就可以用它们组合出变幻无穷的棋局。而我认为,好的程序语言应该像国际象棋去掉像“王车易位”(castling)一类复杂古怪的规则。实际上,好的程序语言会更加近似于中国象棋,而不是国际象棋。中国象棋只有一条规则比较特殊—“蹩脚马”,可是它其实很直观,容易理解。其它的规则,比如兵卒过河才能横行,几乎都画在棋盘上了。

可不要小看国际象棋里这少数几个特殊规则,它们需要在好几个非常特殊的条件满足之后才会生效,而且路线诡异。比如,王车易位必须满足:

  1. 王和跟他换位的车都没有移动过

  2. 王和车之间没有其它棋子

  3. 王不能处于被“将军”的状态而且王在换位之后不能处于被攻击的位置但是车可以在换位后处于被攻击位置

  4. 王和车处于同一条水平线上

另外换位的时候王和车不是直接互换位置那么简单,而是这样的路线:

一条这样的特殊规则就够伤脑筋了,据我所知国际象棋还有至少其它两条类似的规则。它们跟其他的规则组合在一起的时候就产生了组合爆炸效应,你发现每走一步,甚至貌似无关的动作都得检查它们是否会出现。你不得不随时把这么复杂的规则放在脑子里。没事找事也不要找这么麻烦的事啊。

这些规则就像是要你记住 C 语言里的 ++i+i++ 或者 if (x = "foo") {...} 是什么意思。经过多年的痛苦经历之后,你多希望不再需要理解这样的代码。可是一旦这样的规则被加到语言里面,总会有人为了显示自己的水平和记忆力去用它们。不得已,你只好陪他们玩。

如果你觉得多了这些无厘头的规则会让国际象棋比中国象棋难度大或者更加有趣,那你就低估了中国象棋了。中国象棋的“游戏树复杂度”其实比国际象棋还要高,高达 10150,而国际象棋只有 10123。这跟中国象棋的棋盘要稍微大点有关系,但是总比记忆那些麻烦的规则好多了。所以相对来说中国象棋既简单又耐玩。

如果国际象棋还凑合算是简单的话,大部分的程序语言就像是魔鬼棋,飞行棋,或者三国杀。它们几乎完全由类似的特殊规则构成。哇,那么多的人物,道具和特殊技,好玩!可是会玩象棋或者国际象棋的人都会觉得它们无聊透顶。

那么是不是规则越简单越少的棋越好呢?围棋就比中国象棋还简单,那么围棋是不是更好玩呢?我觉得不是的。围棋对我来说太慢,太单调,棋盘太大,耗时太多,而且胜负居然不能一眼就看出来,要数好一会儿!这哪里是在玩,纯粹就是在做组合优化题嘛。我觉得这种任务适合交给电脑去做。所以其实简单也有一个界限,超过了这个界限对于人就没有很大区别了,反而会开始感觉缺少一些东西。

我觉得中国象棋和围棋一样简单,它的规则虽然比围棋多,但是仍然处于人脑容易记忆的范围,而且每条规则都很直接了当,没有很隐晦的条件。中国象棋的长距离武器(车和炮)让它比围棋多了很多乐趣,而对于象,马和王的走法的限制,让它比起国际象棋多了几分安心和舒适。国际象棋的后,两个车,两个相的攻击距离和范围太大,让人觉得眼睛很辛苦,因为每一个位置都可能被从太多个方向远距离攻击。而那个王,由于可以到处乱跑,以至于你感觉不是在抓一个住在戒备森严的城堡里的人,而是一只在野外乱跑的老鼠。

什么游戏会让人觉得有趣,真是一个值得研究的问题。我觉得象棋和我以前推荐过的一个游戏 Braid 里面含有同一种吸引人的设计:屈指可数但又有足够变化的简单规则,组合起来制造出许许多多的变化。这种特征其实也是鉴别一个优秀的程序语言的标准。

程序语言与音乐 

程序语言就像音乐。当听过很好的音乐之后,你会自然而然的厌倦以前曾经喜欢过,为之疯狂过的那些,觉得它们很无趣,甚至很惊讶自己以前怎么会喜欢它们。当有人问你为什么不喜欢他们推荐给你的音乐,你却说不出来。你只是自然而然觉得太单调,不入耳,不对劲,甚至扰乱你美好的心情。你的判断完全是依靠声波对鼓膜的震动而引起的脑电波的起伏,而不带有任何的成见。完全根据这音乐自己,而不需要知道它的作者是谁。就像玩过像《Braid》之类的游戏之后,你再也不想玩像《生化危机》那种搞不清楚到底是自己在玩游戏还是游戏在玩自己的。你的脑子里有一种对“趣味”的新定义,但是你却说不出来它到底是怎么回事。

每当有人问我喜欢什么样的音乐我都不好说出口,因为我最喜欢的音乐家是巴赫(J. S. Bach)。他的音乐不知道为什么,一天听一百遍也不会腻。只有当巴赫的音乐一天放了实在太多遍之后,我才会开始放肖邦的,不过肖邦的一般比较快就腻了。听饱听撑着了,我才开始考虑用 Dream Theater 和少数几首 hiphop 来调一下味。很奇怪的是,我根本不喜欢很多人推崇的贝多芬之类的交响乐,不管是多好的世界级的乐队,不管是现场演奏还是听录音,每次听都打瞌睡,觉得罗里吧嗦滥竽充数的。

巴赫音乐的演奏者里面我最喜欢 Glenn Gould,他演奏的巴赫曲目里面我最喜欢 Goldberg Variations,而他的两次 Goldberg 录音(1955 和 1981 年)里面我只喜欢 1955 年的,虽然当时录音技术落后一些,有一些杂音和 Gould 的哼哼声。我怎么能够区别出自己喜欢哪一个?因为最初的时候它们每个都被我听了几百遍,然后我的心就自然而然做出了选择。

哇,这样说出来总是有附庸风雅之嫌,所以我每次都说“嗯,什么乱七八糟的从古典,rock 到 hiphop 都听点……”倒也差不多是事实,但是我喜欢巴赫显然超过其他人一千倍以上。我每天晚上听着巴赫的音乐睡觉,白天用耳机听着他的音乐上班,没有人知道我在听什么。我每个月付给 Spotify $9.99 享受可以听尽世界上所有音乐的服务,可惜的是过了一两年我仍然每天反复地听那一两张巴赫的唱片,还不如直接把它们买下来。

其实我基本不识谱而且五音不全,也不会乐器,但是听了一阵子巴赫的音乐之后,我再也不想听流行音乐甚至很多其他古典音乐家的作品了。巴赫在我心里丝毫没有名气或者“高雅”的成分,如果他是在街头卖 CD 的音乐演奏者,我一样每天晚上听着他的音乐睡觉。我喜欢他的音乐的原因很简单:有趣听不腻。我反倒觉得大部分人喜欢流行音乐是因为名气和喜欢显示自己,那才是真正意义上的附庸风雅。这里的科学道理就是,绝大部分流行音乐是 4/4 拍,容易唱,但是太单调了,跟一二一齐步走似的,很难做出什么好音乐。然而就是因为这些附庸流行音乐的“风雅”的人,巴赫如果活在今天说不定也就是在街头演奏卖 CD 的命。

程序语言是同样的感觉,这是一个“流行语言”招摇过市的年代。每当有人问我喜欢什么程序语言我都不好跟他说,因为一旦说出来就有显摆之嫌,而其实真正显摆的是其他人。很多人期望你的回答是他所膜拜的那个最近很热门的语言,你一旦告诉他你喜欢的语言就会被冷嘲热讽,因为你的语言不热门。他们会说你是“学院派”,而他们是“工程派”,而其实这只是给垃圾的存在找借口。他们利用你害怕自己被认为是附庸风雅或者居高临下的心理来变相地压制你,让你不敢直率的袒露自己的兴趣。你不敢显示对有些东西的不屑,而他们却可以任意的显示对真正优秀的技术的不屑。你觉得应该手下留情一些,谦虚一些,结果最后一些垃圾一样的语言就骑到你头上来,让你不得不用它们。

用过很好的语言,然后自己设计过程序语言之后,我再也不对很多新的语言,或者有些人很崇拜的古老的语言感兴趣了。我完全是凭自己的感觉来判断,一些所谓的“新特性”其实是老酒换新瓶,或者是勾兑的假酒。程序语言本来就只有那么点东西,为什么有人仍然像对那些扮相的流行歌手一样热衷和疯狂。

我知道这些话说了也白说,因为他们没有用过我用过的语言,他们只看到名字却感觉不到本质,他们靠别人的评价来判断,而不是靠自己的心。所以像音乐一样,只有等有一天他们忽然觉悟,就像很多年前的我一样。

程序语言与武器 

前段时间 AK-47 的设计者 Kalashnikov 去世的时候,我从一篇文章了解到他设计 AK-47 的故事,发现 AK 跟我喜欢的程序语言设计有异曲同工之妙。

AK 简单得就像一把锤子。它身上没有太空时代的材料。大多数汽车修理店都有可以制造出 AK 的工具。

这篇文章首先提到,AK 的高可靠性最主要来自于它的简单,而其实简单也是程序语言最重要的东西。程序员需要解决的问题一般都挺复杂,如果他们的工具再被设计得复杂,那么他们大量的脑力就被浪费在解决这语言的问题,而不是真正需要解决的问题了。

Kalashnikov 开始的时候把任何有可能出问题的设计都排除在外了。

与简单的设计背道而驰,现在很多程序语言为了赶潮流或者吸引眼球,喜欢标新立异,喜欢加入很多“特性”,可是这些特性很有可能不但不解决问题,而且会制造问题。绝大部分程序员都不理解这个道理,所以有些人听说我在设计自己的语言就问我:“它有什么新特性吗?”我没法回答他们,因为我的设计几乎没有新的特性。我现在所做的一切思考和试验都是在去掉不必要的麻烦。一个语言缺少一些好的特性,以后还可以加进去,可是它如果多了一些问题特性,那一旦有人开始用就没法去掉了。

AK 上面没有袖珍和娇气的部件。这样你就不用费事在草丛里,泥地上或者溪流里找它们了。

士兵是人,会摔跤犯错误,程序员也是人,所以程序员的武器应该像士兵的武器一样,方便他们找到问题。可是很多程序语言让程序员犯错误之后花很多时间和精力才能找到错误的所在,浪费大量本来可以用来解决问题的时间。我的前同事 TJ 说他刚进入博士学习的时候花了好几个月,就为了找到 C 代码里面一个指针计算错误,导致内存结构破坏和莫名其妙的错误结果,而出现指针计算错误的位置跟错误结果出现的位置毫无关系。我也遇到过类似的问题。C 语言的指针不就像是某些武器上面的袖珍部件吗?一不小心掉在地上就找不到了。

AK 只有一个复杂一点的部件,那就是它的弹夹。弹夹的设计很大程度上影响到枪的整体性能,所以 Kalashnikov 在上面花了很多设计时间。

这个工程经验其实对于程序语言的设计者有启发意义,因为弹夹与枪主体的接口,和程序语言的函数接口很类似。Tony Hoare 在他的《给程序语言设计的建议》中也提到,函数的调用必须简单而且快速,因为调用的开销会累积起来形成很大的性能问题。可惜的是很多语言没有注意到这个问题,函数调用时总是有一堆的动态检查和重载要做,很大程度的影响了它们的性能。

Kalashnikov 不是天才,他不是为了发明而发明,他解决不了问题的时候就高兴地从别人那里学过来。

这是非常值得我们程序语言设计者学习的。很多程序语言专家都有盲目排斥“对手”的心理,“自己人”的东西就不假思索的表扬,对手的东西就一味的批评。最后的结果是没有把敌人的好东西学过来,让自己人吃亏。在操作系统和数据库等领域也有类似的思维方式,这是非常有害的。

直到被更好的东西取代,AK 会继续和我们在一起。什么才是“更好”,这是由历史和民族来定义的,而不是枪支设计专家。

在计算机的世界里也是一样,程序语言,操作系统,数据库…… 它们的好坏不应该是由它们的设计者决定的,而是看它们是否经得起时间的考验。很多几十年前以为是好的设计,到现在已经很明显的显示出了它们的缺点。这就是为什么我喜欢批评一些语言,操作系统和数据库的设计,因为我看到了它们在历史的长河中已经快要到达终点。自欺欺人的掩盖这些缺陷只会让我们输掉战争。

程序语言与梦中情人 

很多程序员都把选择一种程序语言看成像结婚一样的大事,所以导致很多心理矛盾。一个程序语言真的很像一个人,有你喜欢的地方,也有让你恼火的地方。就像你跟很多人约会,结果没有一个人身上有你喜欢的一切,她们身上总是有你不喜欢的地方。每次遇到新的人,你总是希望她就是那个命中注定的人,可是无一例外的,上帝悄悄在她们身上放了一些你没法去掉的缺点,有时候要到结婚以后才会发现。有时候你有了新的情人,却发现有的地方还是以前的那个好,留恋却又不敢说出来。有时候你喜欢两个人,一人一半,可是传统和法律要求你只能跟一个人结婚,所以你就进入了无穷的烦恼,仿佛错的人是你。无数的小说,电视剧,电影就是为了这个问题被制作出来的。如果有一天编程成为了每个人生活里的一件大事,肯定有作家或者电影公司愿意出品这样的东西。少年黑客的烦恼,Oh,某某语言,想说爱你是一件不容易的事。

不同的是,程序语言并不是上帝创造出来的,而是人类自己。你无法把人大卸八块,只把好的部分组装成你的梦中情人,然而对程序语言你却可以这么做。可惜不幸的是,拥有制造新语言的能力的程序员是非常稀有的,其中有好的品位的就更少了,所以这种人往往被当成上帝。你多希望一个新的上帝能够创造出你想要的语言,去掉其它语言身上你不喜欢的地方,然而他们却一次次的让你失望,就像制造人类的那些上帝一样。所以你等不了了,就跟一个还算谈得来的凑合过了。可是你每天晚上梦见的,却不是睡在你身边的那个人。她不存在于这个世界上,她只存在于你的梦境里。

于是有一天你觉醒了,你决定要成为那貌似可望而不可即的上帝,为自己量身定做一个情人……

程序语言与法律 

法律是一种非常类似程序的东西。法律的语言也很像程序语言。完美的法律应该像一个程序,把案例输入进去,它就会告诉你这件事是合法还是不合法,如果不合法该怎么弥补。当然,法律处理的事情比起程序处理的问题困难太多了,所以没有任何国家的法律可以达到以上的标准。但总而言之,我觉得像程序一样工作就是法律的精髓。

相对而言,有些国家的法律比起另外一些国家要好很多。美国就是这样一个所谓“法制健全”的国家。美国的法律条款都很详细,对每一个名词(变量名)都有精确的定义和“作用域”。每一个条件之下应该怎么办,都有详细的规定(条件语句)。所以法律条文一般都是大条小条的很长,而且所用语言为了严格而显得古怪,一般人不容易读完。但美国有大批经过严格训练的律师和警察,他们就像 CPU 一样,专门学习和执行这些条文。所以一旦有人被指控违法,很容易就能根据法律条款作出判断。如果有人犯法被捕,就算是再有钱的人,也没法绕过法律而不受惩罚。

美国所有的警察,就算交警都是身强力壮,荷枪实弹。对就算家庭暴力这种事情都是说一不二,严格无误,搜身,录口供,谁对谁错毫不含糊。美国法律执行的单位是个人,而不是家庭。中国人几乎都不明白这个道理,这就是为什么有些中国夫妇到美国之后打架,导致其中一方被驱逐出境。相比之下,中国的法律就是一个充满了 bug 和未定义变量的程序。如果遇到家庭纠纷,几乎没有人叫警察,叫来了也不过是做好好先生。哎呀,两口子打架,过一会儿就好了,叫什么警察。中国的法律空子太多,执法又不严,所以很多人钻法律的空子,让老百姓吃亏,甚至警察都腐败掉。

在美国你经常收到银行和商场之类的地方寄来的通知,说法律要求我们告诉你,我们的隐私政策变了。我们根据某商业法规第X条,可以跟以下范围的商家分享关于你的以下信息。说白了,就是说跟他们结盟的商家会得到你的地址之类的信息,方便往你的邮箱里寄广告。在你租房子之前,房东的租约里面都会附带一些公告,比如说,法律要求我们告诉你,我们的房子由于年代久远,有些公寓的大门(而不是内门)上的油漆里面还有 nn 浓度的铅。请参考以下网址了解铅对人体特别是婴幼儿的危害。

为什么银行,商场和房东要告诉你那些呢?不是因为他们好心,而是因为如果他们没有告诉你,一旦有人指控他们就麻烦了。法律不管你是多么有钱的公司,只要违反了法律条文,一律按条例处罚。有时候你会觉得这些东西麻烦,多此一举,然而等到你跟中国的情况相比,才会理解其中的好处。

程序语言也是一样。很多人觉得写类型是一件麻烦事,所以他们用动态语言。有些动态语言(比如 Ruby, JavaScript,PHP)在变量没有定义的时候居然也能输出结果而不当掉。这就有点像中国的法律,过于灵活和柔弱,结果导致错误不能及时被检测,检测到了了也很难找到具体在什么位置。

程序语言与政治 

很多人都曾经妄想着所谓的“社会主义”和“共产主义”能拯救全人类,就像很多程序员都妄想着某一种最近流行的语言能够把他们从繁琐的编程工作里拯救出来一样。几十年前,所谓的“革命者”为了这些很酷很炫的名词,试图把从前的一切文化都焚毁掉。腐朽的资本主义!吃人的旧社会!这就像现在很多 Scala/Clojure/Go 的狂热分子对 Java 之类的语言充满了敌意,一提到这些语言心里就是火。腐朽的 Java,不思进取的 Lisp,Scala/Clojure/Go 就是你们的掘墓人!然而他们没有发现,那些他们试图完全抛弃的语言里面其实有科学合理之处。他们没有看到这些东西之所以存在于那些语言里,是经过了历史的经验教训。这些教训如果不被理解和吸取,当遇到同样的问题,这些新语言就会一样的堕落掉。

有些程序员妄想着 Clojure 和 Go 所谓的 “纯函数式数据结构”,“transactional memory”,“goroutine”等酷毙帅呆的新概念能够一劳永逸的解决并发计算的重重困难,妄想着 Scala 能够让面向对象和函数式编程完美的结合。可是他们没有看到的是人心的险恶,他们就像那些革命者和红卫兵一样,被别有企图的人利用了。在经过深入的研究之后,你会发现这些炫名词其实并不能解决并发计算的关键问题。并行计算之所以困难,是因为物理决定了信息通道的性质。信息只能是单向的,顺序的通过这些信道,而信道的通过速率是有限的。不管你用多么炫的新方式让信息通过它,都不会改变这个事实。所以这些新名词其实不能解决我们的关键问题,要想解决它只有依靠程序员自己的领悟和设计。这就像再先进的工具也不可能帮助你设计出马力翻倍的引擎一样,你必须自己动脑筋,做实验,就像爱迪生发明灯泡一样。


我和权威的故事

backup:

作者:王垠

我和权威的故事

每个人小时候心里都是没有权威的,就像每个人小时候也都不相信广告一样。可是权威就像广告,你听一遍不信,听两遍不信,……,直到一千遍的时候,它忽然开始起作用了,而且这作用越来越强。

消灭广告所造成的幻觉,最好的办法就是去尝试,去实地的考察它。有些虚幻的东西只要你第一次尝试就会像肥皂泡一样破灭掉。可是如果你不主动去接触它,它就会一直在你脑海里造成一种美好神圣的假象。很神奇的一个现象就是,权威对人思想的作用其实也跟广告一样。

上大学以前的人因为没有专业,所以还不怎么崇拜权威,大不了追追歌星,影星,球星啥的。而进入大学之后,就会开始对本领域的权威耳濡目染。一遍,两遍,一千遍的听到同学们仰慕某“牛人”或者“大师”的名字,虽然从来没亲身见过,不知不觉就对这人产生了崇拜心理。Donald Knuth, Dennis Ritchie, Ken Thompson, Rob Pike, ... 就是通过这些途径成为了很多计算机学生的权威。以至于几十年以后,他们的一些历史遗留下来的糟糕设计和错误思想还被很多人奉为神圣。

Donald Knuth

很多人(包括我)都曾经对 Knuth 和他的 The Art of Computer Programming (TAOCP) 极度崇拜。在我大学和研究生的时候,有些同学花了不少钱买回精装的 TAOCP 全三卷,说是大概不会看,但要放在书架上做摆设,镇场子。当时我本着“书非借不能读也”的原则,再加上搬家的时候书是最费力气的东西,所以坚决不买书。我就从图书馆把 TAOCP 借了来。说实话我哪里看的下去啊?那里面的程序都是用一个叫 MIX 的处理器的汇编语言写的。一个字节只有6位,每位里面可以放一个十进制数(不是二进制)!还没开始写程序呢,就开始讲数学,然后就是几十页的公式推导,证明…… 接着我就睡着了。但我总是听说有人真的看完过 TAOCP,然后就成为了大师。比尔盖茨也宣称:“要是谁看完了 TAOCP,请把简历投给我!” 在这一系列的号召和鼓吹之下,我好几次的把 TAOCP 借回来,心想这次一定决心看完这旷世奇书。每次都是雄心勃勃的开始,可从来就没看完过开头那段 MIX 机器语言和数学公式。

看不懂 TAOCP 总是感觉很失败,因为看不懂 TAOCP 就成不了“大师”,可我仍然认为 Knuth 就是计算机科学的神,总能从他那学点什么吧。所以又开始折腾他的其他作品。这就是为什么我开始用 TeX,并且成为中国 TeX 界的主要“传教士”之一。为了 TeX,我把 Knuth 的 TeXbook 借回来,从头到尾看了两遍,做完所有的习题,包括最难的那种“double bend”习题。接着又开始看 MetaFont。开头还挺有成就感,可是不多久就发现学会的那些 TeX 技巧到了临场的时候就不知道该怎么用,然后就全都忘记了。这就是为什么我把 TeXbook 看了两遍,可是看完第二遍之后不久还是忘记得一干二净。

师兄师姐看到我用 TeX,说怎么折腾这么过时的玩意儿。我很气愤他们以及国内学术界居然都用 Word 排版论文,然后我就开始针锋相对,写出一系列煽动文章鼓吹 TeX 的种种好处,打击“所见即所得排版”这种低智商玩意儿。这还不够,又开始折腾 Knuth 设计的 MMIX 处理器,并且认为 MMIX 的寄存器环就是世界上最先进的设计。有几次发现一些无关紧要的小错,就给 Knuth 发 email,居然拿到两张传说中的“Knuth 支票”,并且一度引以为豪。当然像所有拿到 Knuth 支票的人一样,你是不会去兑现它的,甚至有人把它们放在相框里作为摆设。我还没那么疯狂,那两张支票一直在它们原来的信封里。多年以后我到美国想兑现那支票的时候,发现它们已经过期了。

当你心里有了这样的权威,其他人的话你是不可能听得进去的,就算他们其实比你心目中的权威更具智慧也一样。在清华的时候我很喜欢一门叫做“计算几何”的课,就经常跟那门课的老师交流思想。有一次我在 email 里面提到 Donald Knuth 是我的偶像,那位老师很委婉的回复道:“有偶像很好啊,Knuth 也曾经是我的偶像。” 我对“曾经”这两个字感到惊讶:难道这意味着 Knuth 现在不是他的偶像了?在我执意的询问之下他才委婉的告诉我,世界上还有很多很聪明的人,Knuth 并不是计算机科学的一切。你应该多看看其他人的作品,特别是一些数学家的。然后他给了我几个他觉得不错的人的名字。

现在回想起来,这些话对我是有深远作用的。那位老师虽然在系里的“牛人”们眼里是个“研究能力(也就是发paper能力)不强”的人,但是他却对我的人生转折有着强有力的作用。他引导了我去追寻自己真正的兴趣,而不是去追寻虚无的名气。我发现很多人都在为着名气而进行一些自己其实不感兴趣的事情,去做一些别人觉得“牛气”的事情。我真希望他们遇到跟我一样的好老师。

在现在看来,Knuth 的 TAOCP 真的是所谓的“神圣的白象”(white elephant)。很少有人真的看过,却要显得好像看过一样,并且很喜欢。这就让试图看懂它的人更加自卑和着急,甚至觉得自己智商有问题。别人都看过了,我怎么就看不懂呢?其实 TAOCP 里面的大部分算法都不是 Knuth 自己设计的,而且他对别人算法的解释经常把简单的问题搞得很复杂。再加上他执意要用汇编语言,又让程序的理解难度加倍。有一句名言说:“跟真正的大师学习,而不是跟他们的徒弟。”如果你真的要学一个算法,就应该直接去读那算法的发明者的论文,而不是转述过来的“二手知识”。二手的知识往往把发明者原来的动机和思路都给去掉了,只留下苍白无味的“最后结果”。

TeX 其实也是异常糟糕的设计。它过度的复杂,很少有人搞得懂怎么配置。经常为了一个简单的效果折腾很久,然后不久就忘了当时怎么做的,回头来又得重新折腾。原因就是因为 TeX 的设计没有“一致性”,不可以“compose”,所以你需要学太多东西,而不是学习几个简单的东西,然后把它们组合起来。在程序语言设计者看来,TeX 的语言是世界上最恶劣的设计之一。Knuth 的作品里面有他的贡献和价值,TeX 的排版算法(而不是语言)仍然是不错的东西。可是如果因为这些好东西爱屋及乌,而把他所推崇的那些乱七八糟的设计当成神圣的话,那你自己的设计就逃脱不出同样的思维模式,给用户造成很大的麻烦。仍然对 TeX 顶礼膜拜的人应该看一下 TeXmacs,看看它的作者是如何默默无闻的,彻彻底底的超越了 TeX 和 Knuth。

Cornell

可是权威和名气的威力还是很大的。虽然 Knuth 在我心目中的位置不再处于“垄断地位”,世界上可以占据我心里那个位置的人和事物还很多。在离开清华之后我申请了美国的大学。也许是天意也许是巧合,只有两所大学给了我 offer:Cornell 和 Indiana,而我竟然先后到了这两所大学就读。

说实话,Indiana 给了我比 Cornell 更好的 offer。Cornell 给我的是一个 TA 的半工读职位,而 Indiana 给我的是一个不需要工作白拿钱的 fellowship。说实话我从来没有搞明白 Cornell 这样的“牛校”怎么会给我这样的人 offer,GPA 一般,paper 很菜,而 Indiana 却是真正在乎我的。Indiana 的 fellowship 来自 GEB 的作者 Doug Hofstadter。他从 email 了解到我的处境和我渴求真知的愿望之后,毅然决定给我,一个素不相识的人写推荐信。后来我才发现,我的 fellowship 的资金也是他提供的。

可是 Indiana 和 Hofstadter 的名气哪里能跟 Cornell 的号称 “CS前五” 相比啊?Indiana 的 offer 晚来了几天。当收到 Indiana 的 offer 时,我已经接受了 Cornell。Hofstadter 很惊讶也很失望,因为他以为我一定会做他的学生,可是听说我接受了 Cornell 的 offer,他也不知道该怎么办。我只隐约的记得他告诉我,学校的排名并不是最重要的东西……

名气和权威的力量是如此之大,它让我不去选择真正欣赏我并且能给我真知的人。有时候回想起来,我当时真的是在寻找真知吗?我明白什么叫做真知吗?

Cornell 给了我什么呢?到现在想起来,它给我的东西恐怕只有教训,很多的教训。我在一篇老的博文里面提到过,Cornell 的学生一上课就抄笔记,一天到晚都在赶作业。可其实 Cornell 不只是爱抄笔记的学生的天堂,而且是崇拜权威者的天堂。即使你不是那么的崇拜权威,你不可避免的会被一群像朝圣者一样的人围在中间,在你耳边说某某人多么多么的牛。不管你向同学打听哪一个教授,得到的回答总是:“哇,他很牛的!” 然后你就去上了他的几节课,觉得不咋的嘛,可是人家就说那是因为你不理解他的价值。这种气氛我好像在另一个地方感觉到过呢?啊对了,那是在 Google。这样的气氛也许并不是偶然,Cornell 的大部分 PhD 同学当时的最大愿望,就是毕业后能去 Google 工作。当然,后来 Facebook 上升成为了他们的首选。

Cornell 的研究可以用“与时俱进”来形容,什么热门搞什么。当时 Facebook 和社交网络正在崛起,所以系里最热门的一个教授就是研究社交网络的。我去听过他几堂课,他用最容易的一些图论算法分析一些社交网络数据,然后得出一些“理论”。其中好些结论实在太显然了,我觉得根本不需要数据分析就能猜到,真是不觉得有什么特别的。可是 Facebook 名气之大,跟着这位教授必然有出路啦,再加上有人在耳边煽风点火,所以有好多的学生为做他的 PhD 挤破了头皮,被刷下来的就只好另投门路了。每次新来一个教授都会被吹捧上天,说是多么多么的聪明,甚至称为天才。然后就有一群的人去上他的课,试图做他的学生。结果人家每节课都是背对学生面朝黑板,写下一堆堆的公式和证明,一堂课总共就没回过几次头。还不如干脆打印出来让大家自己回家看。下面的人当然就是狂抄笔记,有的人甚至带着录音笔,生怕漏掉一句话。人多了竞争也就难免了。上课的同学们就开始勾心斗角,三国演义的战术都拿出来了。作业做不出来就来找你讨论,等你想讨论了就说自己也没做出来。没听懂偏要故作点头状,显得听懂了,让你觉得有压力。自己越是喜欢的教授就越是说他不咋的,扯淡,然后就自己去跟他。自己不喜欢的教授就告诉你他真是厉害啊,只可惜人家不要我。怎么感觉就跟皇帝的后宫差不多呢 ;-) 直到两年后我离开 Cornell 之前,还有好些同学因为没找到教授而焦头烂额。因为两年内没有找到导师的 PhD 学生,基本上等于必须退学。

当我离开 Cornell 之后,有一位国内的学生给我发 email 套磁(从系里主页上找到我的地址),问我 Cornell 情况如何。我告诉他我都已经走人了,并且告诉了他我的感觉,一天到晚抄笔记赶作业之类的。然后又问我一个刚毕业的 PhD 的情况,我说他水平不咋的,博士论文我看过了,很扯淡,解决一个根本不存在的问题。他对我说的话有点惊讶,但还是将信将疑。为了确保万无一失,他在 visiting day 的时候专程去 Cornell 考察了一下。回去又给我 email,说见到好多牛人啊,大开眼界,哪里像你说的那么不堪。还说跟那位 PhD 的导师谈过话,真是世界级的牛人那,他的博士论文也是世界一流的。我就无话可说了,仁者见仁,智者见智,随他去吧,哎。

结果两年之后,我又收到这位同学的 email,说他在 Cornell 还没找到导师,走投无路了,问我有没有办法转学。

图灵奖 

说到这里应该有人会问这个问题,我是不是也属于那种没找到导师走投无路的人。答案是,对的,我确实没有在 Cornell 找到合适的导师。然后我就猜到有人会说,就知道王垠水平不行嘛,没搞定导师,被迫退学,哈哈!可是事情其实没他们想象的那么简单。作为一个 PhD 学生,不仅必须精通学术,而且要懂得政治和行情。可是由于学生之间的勾心斗角,他们之间的信息互通程度,是没法和教授之间的信息互通程度相比的。这就造成了“学生阶级”在这场信息战上的劣势。

进入 Cornell 之后我上了一门程序语言的课,就开始对这些东西入迷。可是由于“与时俱进”,Cornell 的研究方向并不是那么平衡的发展的,程序语言领域的专家们早已因为受到忽视而转移阵地,剩下一群用纸和笔做扯淡理论的。说实话,在历史上程序语言方向曾经是 Cornell 的强项,出现了一些很厉害的成果。可是当我在 Cornell 的时候,只剩下两个名不见经传的教员,一个助理教授,一个副教授。其实 Robert Constable 也在那里,可惜的是他做了 dean 之后已经没空理学生了,以至于我两年之后都不知道这个人的存在。我当时也不知道 Cornell 有过这段历史,看不到它的研究重心的移动趋势。我不喜欢那个副教授搞的项目,全是在 Java 上面加上一些函数式语言早就有的功能。可是人家做的热门语言,所以拉得到资金,备受系里亲睐,他的学生们也比较趾高气昂。有一次我跟他的一个学生说了我的一个想法,他说:“你那也能叫研究吗?待会儿我给你看看什么是真正的研究!” 其实那只是我的一个微不足道的想法,我也没说那是真正的研究啊,只是随便聊一下而已。我是不可能跟那样的人合作的,所以我就跟那个助理教授做了一点静态分析的项目。当然我们分析的也不是什么好东西,是用 Fortran 写的 MPI 程序。说实话,那个助理教授其实挺有点真知灼见,他有几句话现在仍然在指引我,防止我误入歧途。他也是很谦虚很好的人,可是好人不一定有好报的。后来他没有拿到 tenure 职位,不得不离开 Cornell 加入了工业界,而我就失去了最后一个有可能在程序语言方向做我的导师的人。

没办法,我就开始探索其它相关领域的教授,比如做数据库的,做系统的,看他们对相关的语言设计是否感兴趣。可惜他们都不感兴趣,而且告诉我程序语言领域太狭窄了。我当时还将信将疑,甚至附和他们的说法,可是现在我断定他们都是一知半解胡说八道。如果他们虚心向程序语言专家请教,现在数据库和操作系统的设计也不会那么垃圾,关系式,SQL,NoSQL,…… 一个比一个扯淡。没有办法,我就开始探索其他的方向,我开始了解图形学和数值分析等东西,进展很不错。可是终究我还是发现,我不喜欢图形学和数值分析所用的语言。我想制造出更好的程序语言来解决这些问题。而教授们也能感觉到你不是真的感兴趣,而且他们貌似不喜欢有不同想法的学生,从而会优先考虑对他的东西更加欣赏的学生。

这就让我走到了跟那位向我打听 Cornell 情况的同学差不多的局面,真是心里有无限的苦却没有人可以理解。这时候我想到了系里的一些德高望重的教授,比如得过图灵奖的人,也许这些顶级的大牛会给我指出方向。于是我就联系到一位图灵奖得主,说想找他聊聊。我说我感兴趣的东西 Cornell 貌似并不重视和发展。Cornell 的校训是“any person, any study”,而我却找不到我想 study 的东西。最后我谈了一下我对 Cornell 的总体感受。我说我觉得大家上课都是死记硬背,不是很 intellectual,我不是很确定学术界是否还保留有它原来的智慧和对真知的向往。

我真的是很诚恳的告诉了他这些,只是希望得到一些建议。结果他立马开始用质问的语气问我,你成绩怎么样?考试都通过了没有?哎,说白了就是想搞清楚你是不是成绩不好没人要。怎么就跟高中教导主任一样。于是乎那次谈话就这样不了了之。可是没有想到,这次谈话就造成了我最后的离别。在学生们互相之间勾心斗角,不通信息的同时,系里的教授们其实背后都是“通气”的。他们根本不懂得如何教学,就知道拿作业和考试往学生头上砸,幸存下来的就各自挑去做徒弟,挨不住的就打发掉。这算盘打得真是妙啊。我也不知道他们是什么机制,每个学生对哪些教授感兴趣,他们貌似都了如指掌。然后系里的教授们不知道怎么的,仿佛就都知道有这样一个不知趣的学生,居然敢说学术界的坏话!

大地震前夕的天空总是异常的美。我竟然在过道里看到那位图灵奖教授对我点头致意并且微笑,以前做 TA 时把我呼来唤去还横竖不满意的教授也对我笑脸相迎。我仿佛觉得,我推心置腹的一席话打动了那位德高望重的教授,再加上在图形学和数值计算的扎实进展,给我的学术生涯带来了转机。可是,我那一次真正的领悟了什么叫做所谓的“笑里藏刀”。

由于那个学期上的图形学还有矩阵计算的课成绩都不错,我心想应该能找这两个教授其中一个做导师吧。再加上那些貌似友好的笑容…… 所以没想很多,居然过了一个非常快乐的寒假。没有任何前兆,没有任何直接的通知(email,电话),一封纸信不知道是什么时候默默地进到了我在系里的,基本上从来不看的信夹子里,直到下一个学期开始的时候(2月份)我才发现。信是系主任写的,大概就是说,由于你的表现,我们觉得 Cornell 不是适合你的地方……

我本来就有想走的意思,可就是喜欢呆在一个地方懒得动。如果你们早一点告诉我这个,我还可以申请转学到其它学校。可是都 2 月份了才收到这样的东西,Cornell 啊 Cornell,你让我现在怎么办?我想我可以说你不仁不义吧?

在这个走投无路的时候,我想起了曾经关心过我却又很失望的 Hofstadter 教授。我厚着脸皮告诉他我在 Cornell 很不开心,我很后悔没有认真地考虑过 Indiana。我很想研究程序语言,可是 Cornell 不在乎这个领域。他回信说,没有关系,你能找到自己喜欢的东西就应该去追寻它,这次不要再冲着名气做决定好吗。Indiana 的 Dan Friedman 就是做程序语言的,你可以联系他,就说是我介绍你去的。

于是给 Friedman 发了 email,很快得到了回信说:“王垠,两年前我们都看过你的材料。我们觉得你是一个非常出众的学生。可惜你最后没有选择我们。你要明白,人生最重要的事情不是名利,而是找到你愿意合作的人。你的材料都还在我们这里。现在招生已经快结束了,但是我会把你的材料提交给招生委员会,让他们破例再次考虑你的申请。” 我和 Dan Friedman 的故事就从这里开始了。

常青藤联盟和“世界一流大学” 

我在 Cornell 的经历应该不是偶然,不是因为我比较特殊。跟我同时进入 Cornell 的博士生有好几个几年后没有拿学位就离开了。其中有一个是非常聪明的,我根本听不懂的理论课他还能拿A,可是四年后退学去了 Facebook。有些本科生也告诉我类似的经历,说被系里某些教授“整了”。Cornell 的自杀率居美国大学前列。我走了以后有一次一周之类有三个学生从瀑布旁边的那座桥跳下去。我觉得自己在 Cornell 所感受到的压力确实超乎想象,是有可能把人逼上绝路的。现在回想起来真是可笑,因为对权威和名气的下意识的崇拜,我给了一群根本没有资格来教育我的人向我施加无端压力的权力。

我应该指出,这种现象应该不是 Cornell 所特有的。我对清华,还有 Princeton,Harvard,MIT,Stanford,Berkeley,CMU 等学校的学生都有了解。这些所谓的“世界一流大学”或者“世界一流大学 wannabee”差不多都是类似的气氛。你冲着它们的名气和“关系网”挤破了头皮进去,然后就每天有人在你耳边对其它某些人感叹:哇,他好牛啊!发了好多 paper,还得了XX奖。跟参加传销大会似的,让你感觉个人的价值被完全的忽视。然后就是填鸭式的教育,无止境的作业和考试,让你感觉他们不是在“教育”你,而是在“筛选”你。这种筛选总是筛掉最差的,但也筛掉最好的,因为最好的学生能意识到你在干什么,他们不给你筛选他们的机会。所以剩下来的就是最一般的,循规蹈矩听话的。在这样的环境里,你感觉不到真正的智慧和真知的存在。GRE 考试所鼓吹的什么“批判性思维”(critical thinking )在美国大学里其实是相当缺乏的。学生们只不过是在被培训成为某些其他人的工具,他们具有固定的思维定势,而不是真正的创造者和开拓者。

人们在这些大学里的时候都是差不多感受的,可是一旦他们出来了,就会对此绝口不提。自己身上挂着这些学校的镀金牌子,怎么能砸了自己的品牌,长别人的威风?所以每当我批判 Cornell 就有些以前的同学一脸的着急相,好像自己没有吃过那苦头一样。

再见了,权威们 

亲爱的同胞们,如果你们觉得有了可以在背后说王垠“被Cornell 退学”的机会,那么你们就错了。我之所以可以告诉你们这些貌似不可告人的故事,是因为你们可能也会经历这些事情。对权威和名校的崇拜,让你们成为了被“教授阶级”摆布的傀儡和他们在学术战场上的牺牲品。我很幸运的遇到了像 Hofstadter 和 Friedman 这样的好人,而你们也许就没有这么幸运。

几经颠簸的求学生涯,让我获得了异常强大的力量。我的力量不仅来自于 Friedman,Dybvig 等教授的教诲,而且在于我自己不懈的追求。机会只亲睐有准备的头脑,并不是每个 Friedman 的学生都可以像我一样在一个星期之内解决十多年才完成的研究,完全独立的进行思考。我可以说,这个领域在过去一个世纪的研究很少有逃脱过我的洞察力和直觉的。我看到一个东西一般很快就会知道它到底会不会管用,我经常发现一些被认为很牛的设计其实是在解决一个根本不存在的问题,而真正的问题却没有得到有效的解决。这里面很大程度上是历史上权威的阴影造成的,它让人们不敢否认这些大牛作品的价值,不敢抛弃它们,所以他们很多的时间花在了解决历史遗留问题,而不是真正的问题。这就是为什么我的英文blog标题叫做“Surely I Am Joking”,因为它记录了我为什么认为一些问题是根本不存在的,或者是人为造成的。

曾经 Knuth 是我心中唯一的权威。后来我又屈服于 Cornell 和常青藤联盟的权威和名气。我因为图灵的威名而误以为图灵奖得主都是德高望重的前辈。应该说,在 Indiana 的日子里,权威主义的影子也是经常出现的。Indiana 学生们的权威比较特殊一点,不然就是 Dan Friedman,不然就是 Kent Dybvig,不然就是 Tony Hoare 之类的。所以你有时据理力争的时候就会听到人这样跟你辩论:“Kent 说……” 不管你说什么,他们都想抬出一个明星来压倒你。我很尊敬 Friedman 和 Dybvig,但我也看到他们的一些思维方式并不是那么的正确,我从来不引用他们的话作为理论依据。我也不喜欢 Indiana 同学们的这种崇拜权威的行为。

在一而再再而三的上当受骗之后,我终于把所有的权威们从我的脑子里轰了下去。这些权威包括所有大学的所有教授,所有的图灵奖得主,Unix 和类似操作系统的设计者,所有的程序语言设计者,图灵,他的导师邱奇,他的师兄 Kleene,被程序语言研究者奉为权威的逻辑学家们比如 Per Martin Lof,各大IT界“牛公司”,美国国防部,美国宇航局,…… 我现在的实力其实超越了 Cornell 和其他任何“牛校”的教授。我的学识不再接受学术界和任何人的评价。我们完全处于平起平坐的低位。如果你觉得你心目中的超级偶像在我之上的话,请先问问我对他们的博士论文或者图灵奖作品有何评价 :-)

不再是我心目中的权威并不等于我鄙视他们或者不尊敬他们。他们在我的脑子里失去的只是他们在很多其他人脑子里的那种被膜拜的地位,那种你可以用“XX人说过……”来压倒理性分析的地位。现在他们在我心目中是一群普通的,有血有肉,有好心肠或者坏心眼的,高傲,谦虚或者虚伪的人。他们设计的东西,好的地方我可以借鉴,但是没有任何人的东西我是不加批判全盘接受的。我深深地知道接受错误的想法的危害性,所以我也希望大家都具有批判的思维,不要盲目的接受我说的话。我不喜欢“大神”或者“牛人”这种称呼。

最后我希望国内的同学们,不要盲目的崇拜国外的所谓“大师”,“牛校”或者“牛公司”。祝你们早日消灭掉心里的各种权威以及对他们的畏惧心理,认识到自己的价值和力量。

新年快乐!


为什么说面向对象编程和函数式编程都有问题

backup:

作者:王垠


我不理解为什么人们会对面向对象编程和函数式编程做无休无止的争论。就好象这类问题已经超越了人类智力极限,所以你可以几个世纪的这样讨论下去。经过这些年对编程语言的研究,我已经清楚的看到了问题的答案,所以,我经常的发现,人们对这些问题做的都是一些抓不住要领、无意义的争论。

简言之,不论是面向对象编程还是函数式编程,如果你走了极端,那都是错误的。面向对象编程的极端是一切都是对象(纯面向对象)。函数式编程的极端是纯函数式编程语言

面向对象编程的问题 

面向对象的问题在于它对“对象”的定义,它试图将所有事情就纳入到这个概念里。这种做法极端化后,你就得出来一个一切皆为对象思想。但这种思想是错误的,因为

有些东西不是对象。函数就不是对象。

也许你会反驳,在Python和Scala语言里,函数也是对象。在Python中,所有的含有一个叫做__call__的方法的对象其实都是函数。类似的,在Scala语言里,函数是拥有一个叫做apply方法的对象。但是,经过认真的思考后,你会发现,它混淆了源祖和衍生物的概念。函数是源祖,包含函数的对象实际是衍生物。__call__和apply它们自身首先就是要定义的所谓“函数对象”。Python和Scala实际上是绑架了函数,把它们监禁在“对象”里,然后打上“__call__” 和 “apply” 标签,把它们称作“方法”。当然,如果你把一个函数封装到对象里,你可以像使用一个函数那样使用对象,但这并不意味着你可以说”函数也是对象“

大多数的面向对象语言里都缺乏正确的实现一等(first-class)函数的机制。Java语言是一个极致,它完全不允许将函数当作数据来传递。你可以将全部的函数都封装进对象,然后称它们为“方法”,但就像我说的,这是绑架。缺乏一等函数是为什么Java里需要这么多“设计模式”的主要原因。一旦有了一等函数,你将不再需要大部分的这些设计模式。

函数式编程的问题 

相似的,函数式编程走向极端、成为一种纯函数式编程语言后,也是有问题的。为了讨论这个问题,我们最好先理解一下什么是纯函数式编程语言。出于这个目的,你可能需要阅读一下Amr Sabry先生(他是我的博士导师)的What is a Purely Functional Language。概述一下就是,纯函数式编程语言是错误的,因为

有些东西不是纯的。副作用是真实存在的。

所谓纯函数,基本上就是忽略了物质基础(硅片、晶体等)表现的特性。纯函数式的编程语言试图通过函数——在函数中传入传出整个宇宙——来重新实现整个宇宙。但物理的模拟的是有区别的。“副作用”是物理的。它们真实的存在于自然界中,对计算机的效用的实现起着不可或缺的作用。利用纯函数来模拟它们是注定低效的、复杂的、甚至是丑陋的。你是否发现,在C语言里实现一个环形数据结构或随机数发生器是多么的简单?但使用Haskell语言就不是这样了。

还有,纯函数编程语言会带来巨大的认知成本。如果你深入观察它们,你会看到monads使程序变得复杂,难于编写,而且monad的变体都是拙劣的修改。monads跟Java的“设计模式”具有相同的精神本质。使用monad来表现副作用就像是visitor模式来写解释器。你是否发现,在很多其它语言里很简单的事情,放到Haskell语言就变成了一个课题来研究如何实现?你是否经常会看到一些有着诸如“用Monadic的方式解决一个已经解决的问题”这样标题的论文?有趣的是,Amr Sabry先生一起合著了这样一篇论文。他试图用Haskell语言重新实现Dan Friedman的miniKanren,但他不知道如何构造这些monads。他向Oleg Kiselyov——公认的世界上对Haskell类型系统知识最渊博的人——求教。而且你可能不知道,Amr Sabry先生应该是世界上对纯函数编程语言知识最渊博的人了。他们在 Oleg 的帮助下解决了疑难后一起合著了这篇论文。讽刺的是,Dan Friedman——这个程序的原作者——在使用Scheme语言开发时却没有遇到任何问题。我在Dan的代码基础上重新实现了miniKanren,增加了一个复杂的负操作。为了实现这个,我需要使用约束式逻辑编程和其它一些高级的技巧。鉴于用Haskell语言重写基本的miniKanren将两位世界级程序员都难倒了的事实,我不敢想象如果用Haskell的monads如何能实现这些。

有些人认为monads的价值在于,它们“圈定”了副作用的范围。但如果monads不能真正的使程序变得易于分析或更安全,这种“圈定”有什么用呢?事实上就是没用处。本身就跟副作用一样难于分析理解。没有一种东西可以说monads能使其简单而静态分析办不到的。所有的静态分析研究者都知道这点。静态分析利用了monads的本质,但却去除了程序员编写monads代码的负担——而不是增加负担。当然,过度的副作用会使程序很难分析,但你也可以使用C语言写出纯函数,例如:

int f(int x) {    int y = 0;    int z = 0;    y = 2 * x;    z = y + 1;    return z / 3;}   

你用汇编语言也能做到这些。纯函数并不专属于纯函数式编程语言。你可以用任何语言写出纯函数,但重要的是,你必须也应该允许副作用的存在。

回首历史,你会发现,数学上的理想主义是纯函数编程语言的背后推动力。数学函数简单漂亮,但不幸的是,它们只是在你构建原始纯粹的模型时才好用。否者它们会变得很丑陋。不要被“范畴论”等标语吓倒。我对范畴论了解很多。即使是范畴理论学家自己也称其为“抽象无意义”,因为它们基本上就是用一种怪诞的方式告诉你一些你已经知道的事情!如果你读过Gottlob Frege的文章Function and concept,你会吃惊的发现,在他的这篇论文前的大多数数学家都错误的理解了函数,而这仅仅是刚刚100多年前的事。事实上,数学语言上的很多事情都是有问题的。特别是微积分方面。编程语言的设计者们没有理由要盲目的学习数学界。

不要盲目的爱上你的模型 

无论任何事情,当走向极端时都是有害的。极端化时,面向对象编程和函数式编程都试图把整个世界装入它们的特有模型中,但这个世界是在完全不依赖我们的大脑思考的情况下运转的。如果以为你有一个锤子,就把所有东西都当成钉子,这明显是不对的。只有通过认清我们的真实世界,才能摆脱信仰对我们的束缚。

不要让世界适应你的模型。让你的模型适应世界。