最近,我開始關心一些新的程式語言,像是C語言發明者之一的Ken Thompson也參與發明的Go語言,以及在今年五月推出1.0版本的Rust。這兩個程式語言都是系統程式語言,因此格外吸引我的注意。
有Google加持的Go語言問世已經好一段時間,也有一定數量的開發者,像在臺灣,也已經有專門的開發者社群在推廣。
而像Rust,本來是瀏覽器公司Mozilla的員工GraydonHoare自己個人的開發計畫,之後得到了Mozilla的贊助,專門成立一個團隊來開發,而且還將它運用在一個名為ServoParallelBrowserProject的計畫裡。到了今年才有版本號為 1.0 的正式版本編譯器釋出,這說明了其語言功能的完備性,以及編譯器實作的穩定性,都達到了一個里程碑。
最近在中國的程式設計社群裡,開始有愈來愈多的文章提到Rust,甚至給予很不錯的評價,這令我也動起了想了解這個程式語言的念頭。
很多種程式語言同時存在,其必要性何在?
事實上,這個世界上除了我們所熟知的主流程式語言之外,還有著起碼數百個程式語言,大多的程式語言都沒有進到主流的開發領域中。但即使如此,主流的程式語言還是不少,為什麼我們需要那麼多程式語言?為什麼人們還在持續嘗試著發明新的程式語言?即使一個程式語言受到高度的歡迎及使用,也仍然有其他程式語言存在的空間。
為什麼沒有一個唯其獨尊的程式語言,能統治這個世界?
當我們談到程式語言的差異時,很多人會先從語法層次開始談起,就像是某語言的For迴圈是怎麼寫、變數如何宣告、類別如何定義、 ……等等。
有些語法的差異,其實單純只是程式語言發明者本身的偏好,就像在Objective-C裡,喚起物件的函式是用 [oM] 的形式,而在C++ 中則是O.m或O->m的形式。它們本質上的意義是一樣的,即使看起來語法不同,但其實分別並不會太明顯,對寫作上的影響也不大。
真正影響一個程式語言本質的,不會是表面上的語法結構,而是透過這些語法還有其他面向所表現出來的精神。
舉例來說,Java的語法中有New,可以從Heap中配置物件的記憶體,進而產生出一個新物件,卻不像C++ 中一樣有New還有對應的Delete,足以將物件所配置的記憶體歸還到Heap裡(當然在解構式裡可以進行一些除了歸還記憶體以外的動作)。
而之所以有New而無Delete,是因為Java語言中有個垃圾收集器(GarbageCollector),當判斷到物件不再被參照時,即會自動回收其佔用的記憶體。因此,Java的程式設計者,基本上只管產生物件,至於何時回收物件的工作,就通通交給垃圾收集器了。
從這樣的角度來理解,就可以看到Java具有垃圾收集器這機制的層級。但是,若是更深一層的思考,為什麼Java會導入垃圾收集器呢?這就關係到一個程式語言所信仰的價值觀和哲學了。
對於每個程式語言背後的核心設計理念,要去理解
整個來看,對Java語言來說,最重要的事情之一,就是開發的生產力,因此,語言的設計就把如何提高開發時的生產力,當做核心要務。
我相信,有很多的程式語言在設計時,都想著要提高生產力,但是各家想要達成這個目標的手段卻又有不同了,在此展現出基本信仰的不同。Java提高開發生產力的手段之一,就是避免程式設計者犯錯,因此,有許多設計都是圍繞在避免程式設計者犯錯為中心的。
Java引入垃圾收集器,目的就是為了避免程式設計者犯錯。Java在語法上是承襲著C及C++ 的體系,所以有很多特質和它們也很相像,但垃圾收集器是一個很大的差異,而這個差異也正是Java想要改進的地方。
觀察C甚至C++的開發經驗,不難發現,記憶體的配置和釋放,向來都是程式設計者很容易踩中地雷之處。尤其像C++中,既有建構式,又有解構式,在建構式裡,提供程式設計者操控物件生成時諸般行為的彈性,而在解構式裡,同時也允許程式設計者在摧毀物件時,自訂相關的回收程序。
C++的基本哲學之一,就是強大、有高度的彈性,這對程式設計者來說,絕對有好處,但所衍生出來的複雜度,就容易產生地雷,程式設計者一不小心就會踩中。
一個因為不小心而造成的錯誤,可能要花費數倍甚至數十倍於撰寫該程式碼的時間及心力,才有辦法予以修正,而倘若是記憶體配置及操作上的問題,常常更是棘手。相信C++的程式設計者對於尋找記憶體非法存取(通常會造成應用程式閃退Crash),或是記憶體洩露等問題的痛苦,或多或少都有所體驗吧?改善了這一點,就有機會節省大量被虛擲的光陰。
所以Java沒有指標,沒有辦法像C/C++一樣的,隨意指到記憶體空間中的任意處,這樣的設計等於自我在先天上就除去了一個強大的武器,但同時間也帶來了避免犯錯的機會。只要能夠利用語言的語法及機制設計,來盡量避免程式設計者犯錯,就可以提高生產力。我想這是Java語言的中心思想之一。
乍看相似的程式語言之間,仍有其根本差異
即使Java在語法上和C及C++頗為相像,但其實它們骨子裡的精神,已經截然不同。即使是C和C++對比起來,個性也是相差甚遠。這就是我所謂真正影響一個程式語言本質的,不會是表面上的語法結構的意思所在。選擇C語言這一族系的語法元素,我想,最多的考量,還是因為想要吸引更多已經熟悉此套語法元素的程式設計者入門、上手。但這些看起來頗為相像的程式語言之間,終究還是各自有截然不同的靈魂。
當我們在檢視、了解新的程式語言時亦然。我們想要認識的新語言,就像是Go或是Rust,它們也同樣承襲了C這個族系的許多語法元素,但是,這不影響到它們擁有自己獨立的設計哲學。事實上,它們也都各自瞄準自己想要解決的問題,以及設定其應用領域。就像這兩個語言,都在語言層級就將並行性予以考量進來一樣。
為何新的程式語言仍在持續誕生?因為外在環境一直在變
隨著時空環境的變遷,人們對於軟體開發活動的特性更為了解之後,更明白程式語言應當如何改進才能帶給開發者更多的好處。同時,也隨著外在條件的改變,像是主流的應用架構、或是硬體的效能,也讓一些原本不可能實現的語言機制,得以在現實的環境中被應用。
而這是之所以持續有新語言,被發明、甚至被廣泛使用的原因。
但永遠很難有一個程式語言,足以滿足各種應用上的需求,而且,歷時不衰。因為技術在進步,人們對軟體的了解,也一直在進步。
這個世界無疑的會需要新的語言來注入新血,這些新的後起之秀,帶著新的觀察及洞見,提供更新的程式寫作時的表述方式,力圖改變程式設計者的開發生活。
因此,我們在了解每一個新的語言時,所比較的,絕對不是表面上的語法差異,而是要從這些語法的差異中看到語言本質上的個性及靈魂,也才能夠明白這個語言的精神,以及怎樣才能將它發揮到極致。