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