動態型別的衰退

Du Spirit
Java Magazine 翻譯系列
5 min readFeb 3, 2018

曾被視為便利的特性所帶來的麻煩已比其帶來的價值還多

Translated from “The Decline of Dynamic Typing” By Andrew Binstock, Java Magazine January/February 2018, page 5–6. Copyright Oracle Corporation.

如果您有在專注程式語言的興衰,無論是在扶手椅上,舒適地用著您喜歡的工具但仍對其他人的選擇感興趣;或是在鍵盤上,樂於嘗試各種新方言。您會注意到現代語言設計一個明顯的趨勢:偏好靜態型別。

看過去十年加入的主要語言像是 Go、Swift、Kotlin 及 Rust,它們全是靜態型別,此外,曾經是動態型別的語言已加入靜態型別,最顯著的例子是最近 JavaScript (精確地說是 ECMAScript) 的更新。Apple 選擇用 Swift 取代動態型別的 Objective-C 也是隨著這趨勢。

快速回顧一下,靜態型別指的是一個型別系統,能在編譯期間知道每筆資料及每個表示式的型別,具體來說,這意味著該類語言不允許在執行期間解析型別。例如:在 JavaScript (動態型別語言) 中,一個使用 var 宣告的變數,而不是以特定型別宣告,在同一個程序的不同時間點,可能是一個字串、一個數字或是一個布林值。與之相反的,靜態型別,像是 Java 中的型別,強制您在定義變數時宣告型別。

靜態型別提供多個重要的優點。第一個優點是編譯器能進行重要的程式驗證,由於編譯器知道例如 i 已被宣告為整數,它能檢查所有使用到 i 的地方是否如預期或是能支援一個整數。同樣,當擁有完整的型別資訊,靜態程式碼分析工具可以有更多的能力。

第二關鍵的好處是效能。執行期間,檢查每個變數的型別及該變數有哪些函式,對執行環境是一個重大的開銷,對靜態型別語言而言這是不需要的。這也是多數傳統動態語言如 Python、Perl 及 Ruby 執行速度較其他靜態型別語言慢的部分原因。一個例外可能是 JavaScript,它較其他動態語言快許多,但這速度是 Google 和 Microsoft 在各自的 JavaScript 引擎投入大量投資帶來相對較近期的改善。

最後一個好處是可維護性,在我的觀點中,是逆轉動態語言趨勢的主因。首先,是可讀性,當型別是以靜態方式宣告,程式是較容易理解的,因為它能精確地告訴您在看什麼,除錯時,這是十分寶貴的資訊,在單步執行時,改變變數內容型別的程式可不是任何人的樂趣。動態型別也會在發現錯誤時,引入不確定性,假設一個變數 i,先前是個整數,現在是個字串,是開發人員本來想打 u 卻打錯字或是刻意要重複使用該變數?如果是後者,您如何理解 i 在程式碼中其他地方的意圖?這些問題在程式還少時是能承受的,但隨著程式變龐大就會變得十分棘手。這問題,就如它在大型專案中出現的那樣,是 Microsoft 建立 TypeScript 的主要動機,在 JavaScript 之上增加一個主要的特性:型別。

當 PC 硬體已足夠強大,能運行需要執行環境支援的語言,動態型別盛行於 1990 年代中期流行的語言 (Python、Ruby、JavaScript 及 PHP 都在這四年間出現 [譯註:1991 ~ 1995,Python 是 1991 年,後三者都是 1995 年])。當時,工具仍很原始,編譯時間很長,因此動態型別促進了快速及簡易開發,是一個值得歡迎的進展。雖然動態語言仍十分流行,但 15 年後,當程式碼越龐大,效能變得越來越重要,維護的成本持續上升,動態型別的代價更明顯。當然,動態型別語言還會陪伴我們很長一段時間,但不會是許多新語言選擇擁抱的模型。

譯者的告白

跟我共事過的人應該都知道我是極度不喜歡動態型別語言的人,看到這一期 Java Magazine 的文章,特別有感,所以隨手翻譯了一下。加入既有專案那是無可奈何,原本專案用什麼語言就用什麼語言 (所以上述多數種動態型別語言都寫過),但除非有必要,不然不會在開啟新專案時選擇動態型別語言,最大的原因跟上述的第三點一樣:可維護性。當在讀一段程式碼或修改別人的程式碼時,不知道型別,呼叫 method 時要擔心有沒有這個 method 時,那多麼令人討厭,當執行期間或是 production 環境掛掉才知道這個變數不是某某型別,或是這個物件沒有這個 method 時,那很讓人火大。

有人可能會說應該要寫 (單元/整合/UI) 測試啊,但靠測試來檢查型別對不對根本就是本末倒置,因為很多整合的 case 根本不會針對型別去測試,之前遇到一個案例,某人改了某個 ruby 物件的 property 名稱,該物件的單元測試過了 (廢話),但某個 erb 頁面會使用這個 property,原先會正常顯示,改完後卻一直等到 sprint 快結束時才被發現壞了,中間有一段不算短的時間都沒有任何人發現,因為沒有人回去看上個 sprint 或上上 sprint 已經開發完的頁面對不對,本來 compiler 可以快速檢查出來的問題,卻變成要用成本很高的 UI 測試才能找出來,我還真不想做這種蠢事。

--

--