免责声明:整篇文章或者是我的推测与愿望,或者是一篇控告。
介绍:批评Objective-C
程序员,旁观者和学者已经批评Objective-C好长时间了。
关于语言和API的抱怨包括缺少多元组,子串(slices),散列表或者在语法级别类似的结构;缺少编程模板;缺少命名空间;方法缺少默认参数;缺少运算符重载;不成熟的垃圾回收器(iOS上就没有垃圾回收机制);冗长的命名转换;缺少包管理;对商用API比如REST、SOAP、SQL等待缺少原生的支持。即使是最经常被嘲笑的方法的方括号格式也应该改变(或者修正)。
这些孤立的批评都不是代替Objective-C的理由。你可能会说如果Objective-C需要改变这么多方面,那么也许最好的方式就是替换掉整个语言。
但是代替主要的开发语言对于开发团队来说是不悦的。苹果也不会为了美学或者极小的特色来做这个事情。代替某一语言的理由必须是更实用和更功能化的。
更为中肯的是一个Objective-C不能修改的特性:关于C本身的抱怨,特别是C中的指针。
如果说与C在代码层兼容是Objective-C最好的特性,直接内存模型就是Objective-C的最不受欢迎的特性。
直接访问内存模式在正在逐渐消亡
直接访问内存模式,特别是使用C语言的项目正在变得越来越不受欢迎。
根据下面的表单20个最流行的编程语言(不完全是一个科学资源,但是也具有说服力),仅仅32%的人仍然使用直接存储模式的语言(C,C++,Objective-C,Pascal,Delphi)。在10年的时间里,你可能不会在除内核、驱动、游戏和底层嵌入式软件之外的项目中看到直接访问内存的语言。
这意味着无论苹果是否反对直接访问内存的APIs(很可能他们不会),无论他们是否引入一个新的语言,苹果的官方程序环境会具有虚拟存储模式(an abstracted memory model)。
在存储虚拟化中的程序虚拟机的作用
技术上看,当前Objective-C的垃圾回收器是一个虚拟存储模式。但是我把它排除在外因为它不是完全的虚拟存储模式,而且只要Objective-C包含C指针,那么它就永远不会是。
仅仅因为你不需要释放内存,并不意味着不会有其他内存问题。你仍然有指针,这些指针仍然可能指向某些东西。你仍然可能数组越界。你仍然可能使缓冲区溢出。你仍然可能碰巧重写了某一个内存区域。甚至可能你使垃圾回收器回收了正在使用的资源。
这是相当抽象的漏洞。
不用一个真正意义上的虚拟机来创建一个虚拟存储模型是可能的(可以参见下面一个不同方式)但是虚拟机允许你锁住虚拟部分因此不会有任何意外的漏洞。你不再需要指针。你不会轻易地覆盖内存。你无法使数组越界。你无法是缓冲区溢出。
虚拟机通过移去提供直接获取内存的指令而实现上述功能。相反,虚拟机上的指令只与对象、属性和值相关联—你不能获取内存的错误区块,而且垃圾回收机制相对传统方式也会是更有效的,因为所有存储的引用是完全确定的。
关于我提到的“虚拟机”的定义:“虚拟机”描述一台没有直接依附于某一特定机器的计算机,而是映射到某一确定的机器。这种映射正常情况可以通过运行解释(比如脚本语言),运行仿真(比如计算机模拟器)或者实时编译为原始机器语言(比如java的JVM)来实现。无论该“虚拟机”的运行方式如何,关键是程序员只需处理虚拟方案而目标机器的确切结构和行为不会直接涉及到。
平台独立性
第二个关于虚拟机的讨论与语言关系不大:平台独立性。
苹果在17年中两次改变CPU架构。不久又将发生一次。虽然向intel CPUs的改变难以置信的顺利(我对它的无缝转变感到震惊),但还需要相当长的时间来等待大部分程序的intel版本以及其他的开发者来完成全部的转换工作。
考虑到苹果在iOS设备上的额外努力,设想一系列不同的CPUs可以在一套设备上使用是可能的,fat binaries只能为少量CPUs提供便利。如果苹果打算使用一系列不同的CPUs,那么单独的字节码运行是唯一的方式。
好的编程应该避免代码只能适用于某一特定的硬件设备。将CPU和平台从程序中独立出来是一个符合逻辑的步骤。
在不同CPUs上运行这个主题,一个有趣的点是苹果最近确实引入了一个新的平台独立的语言:OpenCL,该语言在JIT编译虚拟机上运行。我无法预见是否有趋势要利用OpenCL重新实现Cocoa(这个方式比Objective-C更加神秘)但是实现它的技术当然是存在的。
不利用新语言的虚拟机
需要注意的一点就是在新语言之前可以先引入虚拟机。
如果苹果判断对交互存储管理的恐惧使开发者望而止步,但是又不准备一步完成到新语言的转变,先转换到虚拟机(获得虚拟存储模式的好处)是可能的,而同时使得代码层的变动相对更小。
虽然这看起来是个奇怪的事物,但确实有两项好处。
第一个是在虚拟机内运行的Objective-C可以更简单地与虚拟机外的原始Objective-C建立桥接。如果你记得苹果曾经放弃桥接Java和Objective-C,当时最大的技术难点是Java看待一个对象的动态执行性不如Objective-C,而且Java不能跟踪在Objective-C这一端方法和指针的改变。桥接一个虚拟机中的语言到虚拟机外的语言在这个模型里是相对简单的。
第二个是当前Cocoa是适合Objective-C特点设置的。仅使用虚拟机可以保持Cocoa本质的相似性,使得苹果的开发工作更简单。
更新:Jesper曾经指出这一点而且解释为什么虚拟化Objective-C同时保持与非虚拟化的Objective-C的兼容性可能不是一个好注意。
简而言之:,一个虚拟化版本的Objective-C(比如它之前的C++.NET)需要移去大量的语言特性或者它需要抛出运行异常如果你的代码违反了一系列的规则(相当于没有解决虚拟存储问题)。
一个不同的方式
当然,仅仅因为上面所提到的优点,并不意味这虚拟机肯定就是Mac 开发改善下一个步骤。
确实存在可编译,垃圾回收,存储安全的不需要虚拟机的语言,该语言完全满足虚拟存储模式的要求,:Google’s Go language就是一个例子。
让苹果接受Go是不可能的。不要提Go还在开发,一个问题就是Go不能与Objective-C桥接。实际上,Go目前还不能轻易地与C或者C++桥接。
确实转移到一个类似Go的语言上来需要一个空白间断,即会有向前的兼容性的问题。这个间断是可能的(Carbon引入到Cocoa就是这样一个间断),我认为更可能的方式是苹果会选择通过使用自定义语言或者某一已存语言中的自定义变量来保持一定的互用性。我这样怀疑的原因是苹果曾经有机会来代替Cocoa(在iOS上),但是它选择保持原有设计。我怀疑他们已经决定在未来Mac上继续使用Cocoa,即使语言和环境已经改变了。
虚拟机能够提供的更好的向前兼容性,桥接性和可移植性在加上现代JIT出色的运行能力,导致我认为非虚拟机的选择不能提供足够的灵活性而且非虚拟机的方式带来的优点并不足以抵消语言改变而带来不便。
结论
显然,我热爱Objective-C和Cocoa;我确信从我的博客和关于它的特点的辩论文章可以明了我的观点。我并不同意上面所列出的大部分的批评。我认为这些批评是浅薄,或者他们太哲学化了而且技术上被误导。
但是Mac开发者无法对抗一个势不可挡的完全虚拟化存储模型的趋势,这个趋势已经在Mac相关开发之外大范围的展开。
更进一步,我不认为朝向虚拟机的趋势是值得去反抗的。当前Cocoa和Mac编程的主要特色:关注细节,widget运行方式,方法,类和APIs都不会改变。实际上,大部分Cocoa仍然可以保持原样。
最终我确信Apple会转向一个新的语言;
现在真得不用着急做这些。当然iOS设备目前不需要这些。甚至是在Mac上,我认为在某些事情发生之前,还会有几年的警示和准备,当最终发生时不需要强制的转变。
当我说目前不用着急,我意味着:我认为在10年之内,你仍然可以为Mac发布新的,非虚拟机的,Cocoa/Objective-C开发的程序(同时,如果你愿意你仍然可以写Carbon程序)。我只是不认为Carbon会是最普遍的选择。