魏名华

不要偷懒,做更好的自己

Nothing


No Welcome Message

语言的问题

下面是王银博客里提到的一个语言的历史遗留的问题: ++i/i++,以及对这些问题的抨击。

我其实不能确定这是否真的是语言留下来的不好的设计,还是确实只能这样设计,我更倾向于认为,如果是设计失误,语言作者会出面说清楚,也应该这样。

但是,当年我也因为面试问到这些,要去背类似的面试题,头很痛。

最近看winter的《重学前端》,也提到一些,我原本来回搞不懂的js问题,竟然是语言设计本身的历史遗留的错误或糟粕,让我大跌眼镜。

有时候看资料,偶尔也会看到,某某问题是设计失误,语言作者亲口承认的。

那么有没有一个网站,专门收集这些语言设计者或专家承认的,语言自身的设计问题,并讲清楚来龙去脉,避免大家误当成特殊的牛逼的知识来学,还引以为傲。

也许各个社区早已讨论过这些问题,看来应该提供英语水平,去混国外的社区才行。

程序语言的常见设计错误(1) - 片面追求短小

有些人很在乎 i++ 与 ++i 的区别,去追究 (i++) + (++i) 这类表达式的含义,追究 i++ 与 ++i 谁的效率更高。这些其实都是徒劳的。比如,i++ 与 ++i 的效率差别,其实来自于早期 C 编译器的愚蠢。因为 i++ 需要在增加之后返回 i 原来的值,所以它其实被编译为:

(tmp = i, i = i + 1, tmp)
但是在

for (int i = 0; i < max; i++)
这样的语句中,其实你并不需要在 i++ 之后得到它自增前的值。所以有人说,在这里应该用 ++i 而不是 i++,否则你就会浪费一次对中间变量 tmp 的赋值。而其实呢,一个良好设计的编译器应该在两种情况下都生成相同的代码。这是因为在 i++ 的情况,代码其实先被转化为:

for (int i = 0; i < max; (tmp = i, i = i + 1, tmp))
由于 tmp 这个临时变量从来没被用过,所以它会被编译器的“dead code elimination”消去。所以编译器最后实际上得到了:

for (int i = 0; i < max; i = i + 1)
所以,“精通”这些细微的问题,并不能让你成为一个好的程序员。很多人所认为的高明的技巧,经常都是因为早期系统设计的缺陷所致。一旦这些系统被改进,这些技巧就没什么用处了。

真正正确的做法其实是:完全不使用自增减操作,因为它们本来就是错误的设计。

好了,一个小小的例子,也许已经让你意识到了片面追求短小程序所带来的认知上,时间上的代价。很可惜的是,程序语言的设计者们仍然在继续为此犯下类似的错误。一些新的语言加入了很多类似的旨在“缩短代码”,“减少打字量”的雕虫小技。也许有一天你会发现,这些雕虫小技所带来的,除了短暂的兴奋,其实都是在浪费你的时间。