名词王国里的死刑(翻译)

真是惭愧,直到今日才读到这篇文章,原文在这里。我本人大学课程中唯一没选修的语言就是Java,不知什么原因对于Java就是不感冒。虽然由于某些原因做了一阵android的开发,但是这段经历更是让我坚定了“能不写java程序就不写java程序”的想法。这里无意引起“语言之战”,仅是个人喜好问题罢了。


大家好,今天我们来讲述一个有关于邪恶国王JAVA以及他如何在全国范围压迫动词的故事。 警告:这个故事并没有圆满的结局,也不是为了那些心脏脆弱、爱好批评的人准备的。如果你易怒或者喜欢在评论中喷粪,请离开。 在开始之前,让我们来理解一些概念。

溢出的垃圾

(原文‘The Garbage Overfloweth’,th是古英语中的第三人称后缀,涨知识了) 所有喜欢java的人都爱“用用例”,所以让我们使用个用例开始:比如说倒垃圾。“Johnny,把垃圾倒掉!它都快溢出来了。” 如果你是一个正常的、普通的、平凡的、说英语的人并且要描述倒垃圾这个行为的话,你大概会想到以下几步:

  • 在水池下面拿出垃圾袋
  • 把它带到车库
  • 把它扔进垃圾箱
  • 回屋
  • 洗手
  • 躺回到沙发上
  • 继续打游戏(或任何刚才正在做的事)

即便你不说英语,但你仍然会想到和上面类似的步骤。无论你讲什么语言或具体做出什么样的动作,扔垃圾都是最终垃圾在外面并且你在屋里的一系列动作。

我们的思考总是伴随一系列或勇敢、或猛烈、或热情的动作:我们生活,我们呼吸,我们走路,我们说话,我们大笑,我们痛哭,我们期望,我们恐惧,我们吃,我们喝,我们停,我们走,我们倒垃圾。更重要的是,我们可以自由的去做、去行动。如果我们仅是阳光下的石头,生活也许过得去,但绝不会自由。我们的自由就是因为我们能做事。

当然我们的思考也伴随着名词。我们吃食物(名词),在商店中买东西(名词),坐在椅子(名词)上,并且睡在床(名词)上。石头(名词)可能砸到你,并且在你的头(名词)上砸出一个包(名词)。名词就是事物,而哪里是没有事物的地方呢?但是它们仅仅是事物:这意味着结束,或者结束本身,或者珍贵的财宝,或者我们平时看到的那些物品的名字。这是一个建筑,这是一块石头,任何一个孩子都能说出这些名词。是发生在名词身上的改变使它们变得有趣。

改变需要动作,动作是生活的调味剂,动作甚至给调味剂调味!毕竟,除非你吃了它们否则它们是没有味道的。名词无处不在,但生活是永远变化的,动词给生活添加了乐趣。 除了动词和名词,我们还有形容词、介词、代词、冠词、虚词等等,这些可爱的词类让我们能够思考、说出有趣的事情。我们所有人都同意它们每个都是重要的并扮演着语言中不同的角色,少了一个都会让语言变得黯然失色。

如果突然没有了动词,大家是不是会感到很奇怪?

让我来给你讲个故事,有个地方真的这么做了……

名词王国

java国王用铁腕统治着王国,不准许人民像你和我那样思考。正如你看到的,在java王国中国王规定名词为最重要的一等公民,他们穿着着由形容词提供的华丽服饰。而形容词作为名词的跟班,很庆幸自己没出生在动词家庭。

因为动词在这个国度里生活糟糕透了。

在java王国,国王规定动词是名词的所有物,但动词不仅仅是宠物;整个王国的劳动都是由动词做的,事实上他们是王国的奴隶,类似农奴或者合同工。java王国的居民对目前这种状况相当满足,并且没有意识到这件事可以有任何改变。

动词在整个王国负责所有的劳动,但他们还是被所有人歧视。甚至不准许动词自由活动,如果动词出现在公共场合,那他一定会被名词逮捕。

尽管“逮捕”本身也是动词,但他们也不能单独行动,你必须创造一个“逮捕者”来协助逮捕。但是“创造”和“协助”也是动词啊,于是“创造者”和“协助者”带着他们卑贱的动词“创造”和“协助”出现了。

国王在他的上帝“Sun”那里得到神俞,要将动词在王国中全都驱逐出去。如果那一天真的到来了,一定会需要最后一个动词去做这些事情。根据国王残忍的幽默感来猜测,这个动词一定是“执行”。

“执行”和他的亲属们“运行”、“开始”、“做”、“干”可以通过搭配不同的执行者来替代相应的动词。需要等等?等待者.执行();需要刷牙?刷牙者(我的牙齿).开刷();需要倒垃圾?垃圾处理者.开干()。没有动词是安全的,全都可以用名词+运行来替换。

在王国更加狂热的角落,名词已经完全驱逐了动词。你也许偶然会看到还有动词在种地或者倒夜壶,不过一旦仔细观察就会发现:名词可以任意命名“执行”这一动作而不改变自身属性。所以当你看到种地者在“种地”,倒夜壶者在“倒”,注册管理者在“注册”,其实看到的都是邪恶国王伪装在名词面具下的“执行”大军。

邻国中的动词

在其他语言王国中,倒垃圾是一件非常直接了当的事情,就像我们上面描述的那样。在java王国中,数据对象是名词而函数是动词,而在其他王国中动词居民和名词居民是混合在一起的,共同开展它们的工作。

在C、JavaScript、Perl、Ruby这些王国中,他们将倒垃圾分解为一系列的动作——或者叫动词或函数。他们将这些动作以适当的顺序应用于适当的对象(拿垃圾,走出去,扔垃圾等),即使没有多余的执行者或伴随者倒垃圾这个任务也能成功执行。

在这些王国中很少需要为动词创建包装纸一样的名词,他们没有“垃圾处理策略”这样的名词,也没有“垃圾倾倒地点定位者”来寻找倒垃圾的位置,没有“扔垃圾回调者”这样的名词确保你扔完垃圾后回到沙发上。他们仅仅写一些动词来操作名词,并且创建一个主函数take_out_garbage(),来控制用正确的顺序执行子命令。

当这些邻国中需要名词时,通常是提供一种创造名词的机制。如果有聪明人创造出了一种从未出现过的新玩意,比如一幢房子,一辆车,一种比人耕地快的机器,他们会把这些统一称为“类”,并提供给类一个名称、简介、一些声明以及操作指南。

这样做的区别就是当动词可以独立存在时,你不需要创建新的名词来管理他们。

Java王国很瞧不起他的邻居们,这就是编程王国的现状。

如果你看得足够远……

在世界的另一边,有一片贫瘠的陆地,动词才是一等公民。这就是函数式王国,包括Haskellia, Ocamlica, Schemeria和一些其他国家。因为这些国家地处偏远,所以很少和Java王国有接触。也正因如此,这些函数式王国没事的时候也互相攻击来解解闷。

在函数式国家,名词和动词地位是平等的。然而,名词基本上没什么卵用。他们并不在执行或运行过程中起任何作用,活跃的动词把所有的事都做了。这里没有奇怪的法律创造“辅助者”名词去管控动词,所以这些王国中仅有和存在事物相等量的名词。

这样做的后果就是,动词在这里为所欲为——请原谅我的措辞。作为一个外来人,你很容易的认为在这里动词是最重要的居民。这就是这里为什么叫做函数式王国而不是事物王国的原因。

在比函数式王国更远的地方,有一个传说中的世界——终极Lambda。据说在那里没有名词仅有动词!那里存在"事物",但事物都是由动词创造的。甚至连他们的货币——数字都是动词。如果传说是真的,那么就是lambda(),1就是lambda(lambda()), 2就是 lambda(lambda(lambda()))以此类推。在这个神奇的国度,所有的事物都是由基础动词‘lambda’构成的。

老实说,Java王国并没意识到在遥远的地方有其它王国的存在。你能想想他们知道这件事后会有多震惊吗?他们或许会发明一个新名词(比如“厌恶”)来表达他们的新感觉。

Java王国的居民快乐吗?

你也许认为Java王国的居民最多是有些奇怪并且低效罢了,但你能从他们的童谣中知道他们的幸福程度,而这些童谣大多是异想天开的诗。比如Java王国中的孩子经常背诵的警世诗:

For the lack of a nail,
    throw new HorseshoeNailNotFoundException("no nails!");
For the lack of a horseshoe,
    EquestrianDoctor.getLocalInstance().getHorseDispatcher().shoot();
For the lack of a horse,
    RidersGuild.getRiderNotificationSubscriberList().getBroadcaster().run(
      new BroadcastMessage(StableFactory.getNullHorseInstance()));
For the lack of a rider,
    MessageDeliverySubsystem.getLogger().logDeliveryFailure(
      MessageFactory.getAbstractMessageInstance(
        new MessageMedium(MessageType.VERBAL),
        new MessageTransport(MessageTransportType.MOUNTED_RIDER),
        new MessageSessionDestination(BattleManager.getRoutingInfo(
                                        BattleLocation.NEAREST))),
      MessageFailureReasonCode.UNKNOWN_RIDER_FAILURE);
For the lack of a message,
    ((BattleNotificationSender)
      BattleResourceMediator.getMediatorInstance().getResource(
        BattleParticipant.PROXY_PARTICIPANT,
        BattleResource.BATTLE_NOTIFICATION_SENDER)).sendNotification(
          ((BattleNotificationBuilder)
            (BattleResourceMediator.getMediatorInstance().getResource(
            BattleOrganizer.getBattleParticipant(Battle.Participant.GOOD_GUYS),
            BattleResource.BATTLE_NOTIFICATION_BUILDER))).buildNotification(
              BattleOrganizer.getBattleState(BattleResult.BATTLE_LOST),
              BattleManager.getChainOfCommand().getCommandChainNotifier()));
For the lack of a battle,
    try {
        synchronized(BattleInformationRouterLock.getLockInstance()) {
          BattleInformationRouterLock.getLockInstance().wait();
        }
    } catch (InterruptedException ix) {
      if (BattleSessionManager.getBattleStatus(
           BattleResource.getLocalizedBattleResource(Locale.getDefault()),
           BattleContext.createContext(
             Kingdom.getMasterBattleCoordinatorInstance(
               new TweedleBeetlePuddlePaddleBattle()).populate(
                 RegionManager.getArmpitProvince(Armpit.LEFTMOST)))) ==
          BattleStatus.LOST) {
        if (LOGGER.isLoggable(Level.TOTALLY_SCREWED)) {
          LOGGER.logScrewage(BattleLogger.createBattleLogMessage(
            BattleStatusFormatter.format(BattleStatus.LOST_WAR,
                                         Locale.getDefault())));
        }
      }
    }
For the lack of a war,
    new ServiceExecutionJoinPoint(
      DistributedQueryAnalyzer.forwardQueryResult(
        NotificationSchemaManager.getAbstractSchemaMapper(
          new PublishSubscribeNotificationSchema()).getSchemaProxy().
            executePublishSubscribeQueryPlan(
              NotificationSchema.ALERT,
              new NotificationSchemaPriority(SchemaPriority.MAX_PRIORITY),
              new PublisherMessage(MessageFactory.getAbstractMessage(
                MessageType.WRITTEN,
                new MessageTransport(MessageTransportType.WOUNDED_SURVIVOR),
                new MessageSessionDestination(
                  DestinationManager.getNullDestinationForQueryPlan()))),
              DistributedWarMachine.getPartyRoleManager().getRegisteredParties(
                PartyRoleManager.PARTY_KING ||
                PartyRoleManager.PARTY_GENERAL ||
                PartyRoleManager.PARTY_AMBASSADOR)).getQueryResult(),
        PriorityMessageDispatcher.getPriorityDispatchInstance())).
      waitForService();
All for the lack of a horseshoe nail.

(原诗就是那个因为一个铁钉而亡国的,翻译不出来那种java韵味,哈哈)

直到今天,这仍然是不错的建议。

尽管这首诗和富兰克林的原诗大有不同,但这里的居民还是认为他们的翻译很有魅力。

最大的魅力就是大家看到的架构,架构被java国王赋予了极高的荣誉,因为架构完全是由名词构成的。正如我们所知的,在java王国名词就是事物,而事物凌驾于所有动作之上。架构由事物构成:那些可以看到、摸到的事物,宏伟的事物,用棍子抽打而发出美妙响声的事物。java国王十分喜爱这些噪音,他在换车夫时踢轮子中获得极大的满足(he draws immense satisfaction from kicking the wheels when he’s trying out a new horse-drawn coach,没太理解)。无论有什么样的缺陷,事物总是不可或缺的。

作为人类,我们第一本能总是寻找各种庇护。庇护越坚固,我们越感觉安全。在java王国,有很多强大的事物使公民们感到安全。他们敬服那些大规模的架构并认为“这就是最强大的设计”。当他们尝试修改这些架构时这种感觉被强化了,越发感觉架构的力量强的令人生畏以至于没人觉得能够打破这种架构。

在这种强大架构庇护中的好处就是一切都井井有条:你可以在正确的地方发现每一个名词。这里每个故事都有固定的模式:对象的构造是主旋律,每个抽象类都有一个manager,每个manager都有一个run方法。尽管经验不足,但java的臣民们也意识到可以使用这种模式写任何故事。有一种“名词微积分”可以满足你的任何抽象以及计算。所有人都需要足够的名词、名词构造器、遍历名词图的方法以及重要的execute()函数来实现计划。

java王国的居民不仅仅感到快乐,他们自豪极了。

StateManager.getConsiderationSetter(“Noun Oriented Thinking”, State.HARMFUL).run()

正如外界所说“面向名词的思考方式是有害的”。

面向对象编程把名词当作基石,但为什么要把语句写的如此冗长罗嗦?为什么一种概念要比另一种更重要?正如我们想的,并不是面向对象编程使动词变得不重要,而是我们的思维产生了扭曲。我的朋友 Jacob Gabrielso有一次说,主张面向对象的编程就像主张面向裤子的穿衣方式。

Java是一种静态语言,就像其他类似的语言一样,有自身的局限性。但这种极端的面向名词的思考方式(以及编写方式)让人十分烦扰。任何系统都会让你重塑自己的思维以配合系统,但清除独立的动词看起来十分的不合理。

C++并没有这个问题,作为C的超集,它准许你单独定义函数,并且提供了命名空间这个概念。Java通过重载某个类来实现命名空间、用户自定义类型、委托机制、可见型和作用域机制等等。

别误会,我没说C++“好”,但我发现我更欣赏那些比Java更灵活的类型系统。C++有些时候产生的问题足以使听众抓狂并且想要杀掉你(比如,意想不到的段错误和其他难以发现的隐患),并且很难找到特定的语句来精确的表达思维,但它的灵活性远远超过了Java,因为C++提供了动词。谁想使用没有动词的语言说话呢?

Java仅给你提供了一个类模型,无论何时你有了新的想法,你不得不重塑它、包装它甚至揉碎它直到它成为一个名词,即使它最开始时仅仅是一个动作、一个过程或者任何非名词的概念。

我真感觉回到了8,9年前一帮搞Perl的家伙对我说的:“伙计,并不是所有的东西都是对象的。”

尽管很奇怪,Java似乎是面向对象语言中唯一一个完全以名词为核心的语言。在Python或Ruby中你永远也找不到AbstractProxyMediator、NotificationStrategyFactory这类东西,但在Java中却处处可见。可以肯定的一点区别就是在动词上,Python, Ruby, JavaScript, Perl或其他函数式语言准许你声明并传递函数而不用类进行包装。

很明显在动态类型语言中更容易做到这一点;仅在需要的地方通过函数名调用它并传递一个参数即可获取返回值。

很多静态语言也把函数作为一等公民,包括固定类型的语言C/C++,自动推断类型的语言Haskell and ML。这些语言仅需要提供一个语法去创造、传递、调用合适类型的函数即可。

Java没理由不提供一个简单的添加一等函数的方法,最终进入一个成熟的、没偏见的世界准许人们自由的使用动词来实现他们的想法。事实上有一个叫做The Nice programming language 的基于JVM的语言,它提供了一种非常类似JAVA的语法并且提供了使用动词的方法:独立函数。而Java强制你使用CALLBACK、RUNNABLE或者其他匿名接口来把它包装成类来调用。

Sun甚至都没打破他们的惯例——函数必须隶属于类。任何匿名的函数都会有隐式的this指针指向定义它的类;问题解决了。

我不理解为什么Sun工司一定要把Java放置在只有名词的国度,我怀疑这和他们低估用户有关,他们添加了泛型这个更复杂的概念,所以他们明显不再关心语言的简洁性。添加动词并不是一件坏事,就像Java建立的初衷:给程序员工具让他们更多的实现自己的想法。

我真心希望Java能够修正这点,能让我扔垃圾并回到沙发上,或者任何我想要做的事情。