iOS虛擬機對于Cocoa編程是必然的么?
免責聲明:整篇文章或者是我的推測與愿望,或者是一篇控告。
介紹:批評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會是最普遍的選擇。