嘟嘟老窝

上帝给了我一双黑色的眼睛,我却用它来翻白眼......

导航

« 从硬到软——互联网划时代的标志 修改了Blog代码,现在可以生成自定义文件名了 »

【转载+短评】殊途同归 四个程序员的一天

注:此文转自博客园Everything is nothing

【个人评注】:此文引用四个不同程序员(C、JAVA、C#、Scheme)对一个简单运算函数实现的代码来从一个侧面反映语言的发展,抛开文中提到的函数编程这个较专业的名次外,单单只从四种语言实现的代码量来看,颇具有讽刺意味,当然,我并没有要贬低哪一门语言。

计算机语言从诞生到今天走了几十个年头了,从最初的纸孔到今天纯OO的语言+成熟的开发模型+完美的IDE,这是发展的趋势和必然。每天打开自己的Eclipse,翻开打印几十页的开发规范和类库说明,一笔一笔像个小学生那样在田字表格里面学写字一样的搞开发,早已厌倦,如今的我对编程已没有当年那种三月不知肉味的激情。说真的,平时在给别人讲解或者忠告时,都要求OO,要求规范,要求团队,但我骨子里讨厌OO,讨厌IDE,讨厌设计模型,讨厌软件工程,讨厌开发规范这些枷锁。以往的程序员更像是给自己家里盖房子,想怎么盖就怎么盖,墙刷白还是刷红全由我自己作主,现在你进城了,加入了一个工程队,盖的是大楼,所以人家用地基+钢筋混泥土已经搭好了框架,你的工作只是抹砖,哦,明白了,为什么有人说现在程序员像民工,可能就是这个意思吧。也许我属于那种不入流的,土啊土啊土得掉渣的old programmer吧。也许是我真的老了,因该转行了吧。不过还好,世界上总有一类人和你一样的,最近迷上javascript、ruby和python这些动态或纯脚本语言,原因很简单,用它们写代码感觉很舒服,没有过多的条条框框,能充分发挥个人的创造力。

以下为原文

你,一个DotNet程序员,刚刚加入一个新项目组。除了你之外,其他的成员包括:Ceer,一直从事C项目的程序员,他刚刚转入C#不到一个月; Jally,整天抱着本Design Pattern(没错,就是GoF的那本)在啃的前Java程序员;以及Semon,你对他完全不了解,只是听PM介绍说他是搞Scheme的(传说中的第二古老的语言LISP的方言之一)。不过你也没在意,毕竟计算机这玩意,老东西是不吃香的。

周一,刚打开电脑,老板就跑到你们组的办公座面前:“好吧,伙计们,现在有个function需要你们来搞定。具体是这样的:用户输入2个数,并输入一个操作符。你根据输入的情况来得出相应的运算结果。“

Example: Foo(+, 1, 2) = 3; Foo(*, 3, 6) = 18; Foo(/, 2, 4) = 0.5

Ceer最先作出反应:简单嘛,判断一下输入的操作符就好了。说着,他很快在白板上写出如下代码:
    public class CStyle_Calculator
    {
        static public double Foo(char op, double x, double y)
        {
            switch(op)
                case '+': return x + y; break;
                case '-': return x - y; break;
                case '*': return x * y; break;
                case '/': return x / y; break;
                default: throw new Exception(”What the Hell you have input?");
        }
    }
   
Jally只看了一遍,就捂着鼻子连连摇头:好一股的代码臭味【注1】。还不如看我用OO的方法来解决:
    public interface I操作符 //谁说代码不能写中文的?恩恩
    {
        double 运算(double x, double y);
    }
   
    public class OO_Calculator
    {
        private I操作符 m_op;
        public OO_Calculator(I操作符 op)
        {
            this.m_op = op; //依赖注入【注2】
        }
       
        public double Foo(double x, double y)
        {
            return this.m_op.运算(x, y);
        }
    }
   
    public class 加法:I操作符
    {
        public double 运算(double x, double y)
        {
            return x + y;
        }
    }
   
    public class 减法:I操作符
    {
        public double 运算(double x, double y)
        {
            return x - y;
        }
    }
   
    public class 乘法:I操作符
    {
        public double 运算(double x, double y)
        {
            return x * y;
        }
    }
   
    public class 除法:I操作符
    {
        public double 运算(double x, double y)
        {
            return x / y;
        }
    }
   
    public class TheMainClass
    {
        static public void Main()
        {
            I操作符 我的加法 = new 加法();
            OO_Calculator 我的加法器 = new OO_Calculator(我的加法);
            double sum  = 我的加法器.Foo(3, 4);
            System.Console.WriteLine(sum);
            //sum = 7
           
            //其他3个我就不废话了
        }
    }

你看着Jally把白板写得密密麻麻之后,耸耸肩,暗叹,你们这些用java的废柴,就一个运算器还搞出Interface这些东西,烦不烦啊。 让你们见识见识DotNet的强大吧. 那个运算符我直接用delegate传进去不就好了么.
    public delegate double TheOperator(double x, double y);
   
    public class Operators
    {
        static public double Add(double x, double y)
        {
            return x + y;
        }
       
        static public double Sub(double x, double y)
        {
            return x - y;
        }
       
        //乘,除法 我也懒得废话了
    }
   
    public class DotNet_Calculator
    {
        public double Foo(TheOperator op, double x, double y)
        {
            return op(x, y);
        }
    }
   
    public class TheMainClass
    {
        static public void Main()
        {
            TheOperator myAdd = new TheOperator(Operators.Add);
            TheOperator mySub = new TheOperator(Operators.Sub);
           
            DotNet_Calculator dc = new DotNet_Calculator();
            double sum = dc.Foo(myAdd, 2, 4); //sum = 6
            System.Console.WriteLine(sum);
            double sub = dc.Foo(mySub, 3, 7); //sub = -4
            System.Console.WriteLine(sub);
        }
    }
    //dot net 下面还可以用CodeDom动态构造C#代码,然后在内存编译运行。
    //如果觉得专门写个Operators很烦的话,可以试试C#2.0的匿名方法

很好,当你写完代码之后,挑衅的看着Jally,Ceer却开始抱怨起来:”这不就是C里面的函数指针么,我也会...“
“然则DotNet下面的Delegate是类型安全滴...”你继续洋洋得意.
   
而Semon,看了看你们3位华丽的代码,啥也没说,只是在键盘上敲下了2行代码

(define (Foo op x y)
    (op x y))

然后就下班了...

【注: scheme的代码稍微解释下:(+ 1 2) = 3, (* 3 4) = 12.】
至于Semon的解法:
(define (Foo op x y)
  (op x y))

看明白了么,上面的代码只有一个作用:第一行是函数头,定义了一个叫Foo的函数。该函数接受3个参数op, x, y。
第二行定义了函数的行为:把第一个参数op当作运算符,计算后面2个参数。
所以:(Foo + 1 2) = 3. (Foo / 12 6) = 2.

好了好了,不编故事了。
我只是想简单的让大家在繁忙的工作之余,也瞅瞅Function Programming(函数编程)世界的美妙。函数编程,最大的特点是它是将函数作为语言里1st class的元素来对待的。一个函数可以接受另一个函数作为参数,也可以把一个函数作为结果来返回。这样的函数我们称为Higher-order function。

那么,Function Programming和我们传统的面向对象有啥区别捏? 恩,这个嘛,扯得远可以扯到图灵机和冯·诺以曼这2种体系的差异...@_@不过那个太学术性,俺就不说了。不过有句话可以较好的概括FP和OO的区别(好吧,这个也是抄“紫皮书”上面的):

“Pascal是为了建造金字塔...Lisp是为了建造有机体...”“作为Lisp的内在数据结构,表对于这种可用性起着重要的提升作用...”“采用100函数在一个数据结构上操作,远远优于采用10个操作在十个数据结构上工作”“金字塔矗立在那里千年不变,而有机体则必须演化,否则就会消亡”。

而另一个总结得比较好的话是:(同样是抄来的)

一个对象:一组相同的运算上面,外加不同的数据。(想想你的object,是不是这样的?)
一个Closure:一组相同的数据,外加不同的操作。(Delegate就是这样的思想,有兴趣的话也可以去看看Ruby)

基本上,恩,没啥说的了。 如果你感兴趣的话,可以去看MIT SICP的课程(有在线版的,MIT也作为Open Course开设了的)

参考文献:
Java 语言中的函数编程(偶FP的入门贴。查叔叔,我膜拜您)
http://www.hibernate.org.cn/viewtopic.php?t=7569&postdays=0&postorder=asc&start=0

Lambda Calculus
http://www.mactech.com/articles/mactech/Vol.07/07.05/LambdaCalculus/

Java 语言中的函数编程
http://www-128.ibm.com/developerworks/cn/java/j-fp/

【注1】
见Bob大叔的《ASD》一书

【注2】
Flower的依赖注入模式,Ioc容器啥的是这里来的
  • 该日志的引用地址:
  • http://www.duduwolf.com/cmd.asp?act=tb&id=192
  • [轉載] 4个程序员的一天(引用)
  • 薄荷
  • 純粹推此文. 看到嘟嘟老窩的這篇「殊途同归 四个程序员的一天」, 原文出自 Everything is nothing 的「4个程序员的一天」 對嘟嘟老窩寫的個人評註也深有同感... 说真的,平时在给别人讲解或者忠告时,都要求OO,要求规范,要求团队,但我骨子里讨厌OO,讨厌IDE,讨厌设计模型,讨厌软件工程,讨厌开发规范这些枷锁。以往的程序员更像是给自己家里盖房子,想怎么盖就怎么盖,墙刷白还是刷红全由我自己作主,现在你进城了,加入了一个工程队,盖的是大楼,所以人家用地基+钢筋混泥土已经搭好了框...
  • 2005-7-22 19:48:59
  • 1.mornlee | (home)
  • 恭喜进入Programming Menopause ;-)

  • 2005-7-22 11:59:49
  • 2.duduwolf | (home)
  • 编程更年期?晕死,有这么夸张吗?Fury
  • 2005-7-22 12:02:21
  • 3.令狐虫 | (home)
  • 这个例子不好,明显一开始就偏向了Scheme,没有体现FP的真正优势。更跟后面提到的什么“Lisp是为了建造有机体”八竿子打不到一块。

    实际上如果要体现FP的好处,起码要拿一个组合子的例子来,才容易说服别人。
  • 2005-7-22 13:12:24
  • 5.MengYan | (home)
  • BTW:

    名字不允许空格?Why?
  • 2005-7-22 17:26:05
  • 6.duduwolf | (home)
  • 啊,孟岩兄也来了,我在CSDN上经常关注你的!
    至于名字不能为空格我已经修改了,顺便把.和|也加入了,速度可以吧!Biggest smile
  • 2005-7-22 17:45:24
  • 7.linkcd | (home)
  • @令狐虫

    不错,这个例子不能完全说明FP的。不过我只是想简单说说FP的有趣罢了:)
  • 2005-7-22 18:15:37
  • 8.MengYan | (home)
  • to duduwolf

    此孟岩非彼孟岩也 :P
  • 2005-7-22 19:19:51
  • 9.如果你是攻击OOP那么你错了 | (home)
  • 这种函数级别的东西确实不是OOP所擅长的,但是你的这个题目本身就没什么意义,你要打击Java最好的办法是让人拿Java写一个网卡驱动,看他怎么写!而不是拿这种没什么意义的题,举例来说,OOP的支持者照样可以举出适合他们的例子来(比如书店库存管理),不用OOP能累死你!我个人认为每种编程方式都有其有缺点,这一点那帮大师也深有感悟。比如现在的Java,谁能说它是纯OO语言?掺入了范型编程和静态导入,你可以写出C++风格的程序来(当然,只是近似)。我现在比较看好Aop,有了Aop的协助,OOP将会变得更加强大,仅仅OOP是不够的(目前为止,我还是认为AOP要比闭包语言要强)。至于IDE,呵呵,拿是使用的工具,以前的IDE确实比较傻瓜,被高手鄙视也很正常。但是自从用上了Eclipse后,感觉就不同了,我感觉Eclipse是一个越是高手越爱用的工具(象emacs一样,不过比它好上手,而且我觉得代码也更容易看懂一些——我的C++编程很烂的),你觉得那里不爽,写个插件就是了(不过据我看,仅限于牛人),现在的IDE不比从前了,很多大师都在用,呵呵。你觉得groovy比较好,OK,写个插件用吧,不过好像也不用写了,好像已经有大牛写了。嘻嘻
  • 2005-7-23 10:25:41
  • 11.sss | (home)
  • 函数编程语言早就有了,只不过最近突然变得"时尚"了而已。
    这个东西不过是个不成功的玩具,过去不成功,现在一样不会成功。除了解决几个数学问题,没有什么用处。它顶多可以作为oo的一个小小的补充,增加一些编程的娱乐性。
    正是为了使工作变得简单,前辈们才为我们制造了编译器,而fp却让我们用编译器工作的方式思考,真是个自虐的好工具阿,比皮鞭、蜡烛什么的好使多了。
  • 2006-1-31 17:11:05
  • 12.piggy | (home)
  • 在对大规模数据进行并发操作的时候函数编程是有优势的(比如Google的一些算法),OO更适合业务逻辑开发。函数编程语言除了lisp系列的还有ML/Ocaml和haskell,风格差别比较大。
  • 2006-2-15 21:27:19
  • 13.阿怪 | (home)
  • 不是有template<typename T>这招吗?
  • 2006-8-12 1:39:40

反向链接列表

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

日历

<< 2008·1 >>

Sun

Mon

Tue

Wen

Thu

Fri

Sat

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

Search

Powered By Z-Blog 1.4 SP1 Build 50824 - modify by duduwolf

Copyright 1999-2005 duduwolf.com Some Rights Reserved.