如何选择正确的编程语言(2)

在缺少关于空指针,空字符串以及其他异常处理文档的帮助下,根本没法理解作者到底想干什么。这不太好。当然,函数内部可能对输入做了无数的验证,但你必须写一堆针对各种特定输入的单元测试以确保你的假设是正确的。

我所指的“把意思说清楚”是什么意思呢?假设C++在原型中支持以下虚拟语法:

char*@Nullable reverseString(@NonNullableconstchar*foo);

函数原型中加上这些注解有两个好处:

1. 你不需要事先测试foo是不是null。编译器保证会给你一个非null。

2. 明确地告诉调用者你不容忍null。这种表述方式编译器能够明白,优秀的静态分析工具可以检测到这类bug,这是C语言做不到的。

虽然这看起来只不过是增强了一下语法,实际不仅如此,它还增强了语义。如此不论是人或是机器就明白foo这个变量不可为null,否则函数很生气,后果很严重。而且,你给这个函数划定了界限,再不用担心foo可否为null了。

函数式编程并不是万金油:

大家对我的另外一个常见误解是我推崇纯函数式语言。我的确有理由喜欢它们。看到上面那个式子了吗?

c = a + b

如果我想把expr1和expr2的值相加该如何表达呢?

c =(expr1)+(expr2)

如果expr1有附加操作而且会影响expr2的值又该如何表达呢?这并不罕见:

c =(a++)+(a + b);

这里的问题不是你想的那样。我知道你在想什么:“天知道这门语言会如何解释这个式子。万一计算的顺序反了怎么办?”

你想错了。正是由于人们会产生那样的想法,编程语言才会有这样的特点。要解答你的疑问很简单,看看编译手册就知道了。

上面式子的根本问题是我无法知道那样的计算顺序是偶然的还是有意的。我确切地知道上面式子的会做什么,但我无法确定的是,它的计算顺序是不是有意的?我能不能优化那个式子,放到一个循环里去?我能不能在多核多线程的情况下调用它?假设有人问我,如果给z赋值10而不是20,会不会影响c的值,我无法回答。

理论上是无法回答上面那个问题的。当然了我们可以根据经验做加一些断言(assertion)。在断言出了一堆或者一个警告后,理性地说,我们仍然不知道z会不会影响a或者b,最终影响到c。

为什么这很重要

代码的可维护性是建立在代码的可阅读性的基础上的。你知道为什么CSS不好吗?如果仅仅是程序员写错了或者设计者把字体和布局规则混淆了,地球人都知道那还不算太坏。CSS坏就坏在如果不加上大量的注释,人们就无法通过字面上的意思来理解代码的意图。

别忘了基于规则的声明式语言并不是新概念,更不是革命。50年前Prolog就提供了类似CSS的声明方式。今天的Erlang也提供了这类方式,并在业界得到广泛应用。

请看下面这行代码:

div .title #subtitle {color: blue}

如果不加载试一下的话,我敢打赌你完全想不到这会对页面产生怎样的效果。字面上完全看不出跟其它规则的关系,也看不出它如何处理匹配冲突。

因此对于汝等Ruby/Python/Node.js程序员而言,我的建议是,如果你真想超凡脱俗的话,学学谷歌和Facebook。他们使用一些实验性技术,并不是为了取代for-loops,而是用来表明for-loops的意图。快速原型的话选择简单的语言就可以了,当需要准确描述意图的时候才考虑更换编程语言。

命令式语言的必要性:

最后,我想解释一下为什么命令式语言是必要的。看看��面这个驱动程序例子:

setlpt1(00000000b);

setlpt1(00010000b);

setlpt1(00000000b);

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/a4456bceee1b3040d4eb8369e4a03440.html