印象中王垠跟胡正一样是个奇人,不过今天论事不论人,只评论一下他的这篇老文章“Swift 语言的设计错误”。因为版权问题,只贴一下链接:
http://www.yinwang.org/blog-cn/2016/06/06/swift
这篇文章虽然标题很大,但只说了一个具体问题:王垠认为,把array变成值类型用来解决可变性问题不是一个好的解决方法。我不知道他的想法到现在有没有改变,但我的看法跟他完全相反:string、array、dictionary作为值类型,是积极的改变,是让swift这个“2010后”超越上一代语言Java、C#的重要特征。
首先我们要明白,为什么Java、C#等语言会把复杂数据类型作为引用。是因为程序员都觉得它们本来就应该是引用吗?恰恰相反,是因为在实现上,引用类型符合计算机的工作方式。引用本质上就是指针,不同的引用指向同一个内存地址。C语言的指针可不是因为符合人类的思维方式,恰恰相反,是因为这种实现方式最为简洁。要把复杂类型作为值类型,需要付出更多的工作(深层拷贝),花费更多的CPU时间,占用更多的内存。对于可以用于不同平台的C来说,要在几K内存的八位单片机上,把这种设计当成默认的工作方式,显然是不合理的。
但是可以运行慢得要死的Java虚拟机的现代手机等硬件来说(Java爱好者肯定能拿出一百个例子来说明Java并不慢,我一直不明白,byte code和垃圾回收这种机制不可能在所有场合下都能取得比机器代码加引用计数同样的效率这点,怎么会有人不明白,而且下文会说,并不是机器效率越高,一个语言就越成功),值类型在大多数应用场景不再是一个问题。对大型工程来说,人们更看重的是架构层面的问题。把同一段内存,也就是一个object,用不同的reference来表达,这种方式本质上是会造成架构问题的。要求一个程序员在修改一个内存变量的时候,心中时刻记得所有指向同一内存地址的变量,需要时刻记得相关的所有变量,这样的要求会引发更多犯错误的可能。Swift之所以把可变性作为一个重点问题来抓,原因就是在现实中,可变性引发的bug实在太多太多了。因此Swift会强制你在传递或者复制一个对象的时候,除非特别制定,否则默认会真的复制一段内存内容出来,这样可以保证不变的对象是真的不变。
我虽然不同意王垠,但并没有说他是错的。除了运行效率有多重要之外(事实上大家对比iOS和Android应用也可以看出,对现代硬件,byte code,GC,value reference这些都不是deal breaker),从他之前的文章中可以看出,他的论述基于两个假定:
- 程序员应该拥有相当的素质,比如正确理解和运用异常机制,内存管理方式等“基本”的东西;
- 程序员的主要工作是解决算法问题。
这两点不能说不对,但是在实际工程中,基本都是不现实的。第一,现实就是不是所有程序员都是凭着自己的热爱从事这行事业,技术骨干不能把这些人都踢出自己的团队。第二,程序员,尤其是前端程序员,大部分时间在解决业务逻辑问题的时候,使用的算法是庞杂而不优美的:各种例外,分支,新添加的逻辑,会让代码最终变得复杂。在实际工作中,维护代码质量的方式往往是单元测试为主,重构为辅,因为重构本身就很容易引发bug。而要避免问题,在架构设计上强调不可变的重要性,尽一切可能避免质量低下的代码,才是降低项目维护成本的关键。
说的再多就涉及到做事和做人的问题了,就此打住。