献给那些喜欢阅读和创造的读者~ =)
像这样获取和变更程序本身信息的功能,被称为反射(Reflection)。
无论是ActiveRecord的示例,还是Builder的示例,都通过元编程技术对无法预先确定的操作进行了应对,这样一来,未来的可能性就不会被禁锢,体现了语言的灵活性。我认为,这种灵活性正是元编程最大的力量。
我的看法是,一个追求卓越的程序员应该广泛尝试多种语言,但如何他真的这样做了,他一定会在遇到Common Lisp时停下来,因为他发现这门语言是最强的,也是最美的,并且学习过程也是最艰难的,艰难到以至于学成之后,再没有精力也没有必要去学其他语言了。
程序员知道如何让计算机进行演绎推理,因为计算机能够理解其中涉及的数学。但如果想让计算机进行人类赖以生存的这种推测性的(而又常常是正确的)常识推理,就得发明一种全新的数理逻辑。而这正是约翰·麦卡锡为自己设立的目标之一。
通过这种方式,表不仅能够表示构成科学和工程的标准数学结构,还能表示构成语言的语句结构。
我们连书面提案都没准备,申请就得到了批准。很幸运,当时麻省理工的电子研究实验室刚刚与美国军方签署了一份无固定目标的双向合作协议,而相应的资源还没有到位。我想这种灵活的资源调配正是美国的人工智能研究起步领先于其他国家的原因之一。
所有的科学以及专业理论中都引入了常识。当你想要改进理论时,你总要回到常识推理,因为是常识推理主导着你的试验。
明斯基把这种推理形式称为是“非单调的”(nonmonotonic)。经典的演绎推理都是单调的——只要和旧的信息不矛盾,新的信息就不会改变原来的结论。
开启了常识推理的潘多拉魔盒,促使麦卡锡开始研究一种能允许任意加入新的事实的形式体系。
很自然,遵循严格的不变性模型,并发一下子就变成一个比较简单(虽然还是不那么简单)的问题,这意味着,如果不必顾忌对象状态的改变,我们便可肆无忌惮地共享,而无惧并发修改。
面向对象程序设计将状态聚合在对象内部,朝着这个方向又迈了一步。
Clojure避开了大多数面向对象语言浓墨重彩表现的数据隐藏封装的概念
最后要说一点,面向对象程序设计的另一个不足之处是,函数和数据之间绑定过紧。事实上,Java程序设计语言强迫我们把整个程序完全构建在类层次结构上,所有功能都必须出现在高度受限的“名词王国”(Yegge 2006)所包含的方法中。
“对一个匠人来说,创作一件有情调的作品,一定是出于对精湛技艺的追求。如果仅仅是为了现实目的,固然可以写出高质量的软件,代码本身却容易缺乏灵气。”
对一个匠人来说,创作一件有情调的作品,一定是出于对精湛技艺的追求。如果仅仅是为了现实目的,固然可以写出高质量的软件,代码本身却容易缺乏灵气。代码的艺术和美,与文学略有共通之处,在于强大的表现力。缺乏灵气的代码只顾平铺直叙,是没有生命力的机械;好的代码越是简单明了,越是做得到更多事情。
编程的乐趣在于享受这份创造的快感:他不只是在敲代码,而是在开动脑筋调教程序,增益其所不能。甚至会有一刻在心中大呼:终于不再像菜鸟一样写程序了!谁愿做只会搬砖的码农?定要像设计师那样思考,才称得上有手艺的编码匠。
编程本身不难,难的是将问题抽象。
你仔细审视一种语言的内核,考虑哪些部分可以被摒弃,这至少也是一种很有用的训练。在长期的职业生涯中,我发现冗余的代码会导致更多冗余的代码,不仅软件如此,而且像我这样性格懒散的人,我发现在床底下和房间的角落里这个命题也成立,一件垃圾会产生更多的垃圾。
效率低下的软件并不等于很烂的软件。一种让程序员做无用功的语言才真正称得上很烂。浪费程序员的时间而不是浪费机器的时间才是真正的无效率。随着计算机速度越来越快,这会变得越来越明显。
另一种消耗硬件性能的方法就是,在应用软件与硬件之间设置很多的软件层。这也是我们已经看到的一种趋势,许多新兴的语言就被编译成字节码。比尔·伍兹曾经对我说,根据经验判断,每增加一个解释层,软件的运行速度就会慢一个数量级。但是,多余的软件层可以让编程灵活起来。
新语言更多地以开源项目的形式出现,而不是以研究性项目的形式出现。这是语言的一种发展趋势。另一种发展趋势是,新语言的设计者更多的是本身就需要使用它们的应用软件作者,而不是编译器作者。这似乎是好的趋势,我期待它继续保持下去。