每日最新頭條.有趣資訊

一張主流編程語言的變遷圖,講清程序員遷移模式

作者丨apenwarr

譯者丨方彥

我繪製了一個主流編程語言的變遷圖,用以表示程序員在不同語言之間的切換路徑。

關於編程語言,還有很多類似的圖可以表示它們相互之間的演進。不過我並不想從語言設計者角度來說明這個問題,而是想從程序員本身來看待語言演變。雖然兩者間有些接近,但並不完全相同。

從該圖可以看出,如果開始使用的是編程語言 A,下一個最有可能切換過去的是哪種語言。這種推測不是非常科學。不過如果你需要精確的科學,就不會在這裡閱讀這篇文章了,對嗎?也許這張流程圖對我來說,能揭示更多的內容。

聲明:在此處,不考慮程序員最喜歡的是什麽語言。人們可以在任意兩個語言之間切換,也可以學習很多種語言、然後選擇最適合工作的一種語言。本文中的觀點有一定的傾向性。

在接下來的篇幅裡,我所闡述的均為個人觀點。為了不影響讀者閱讀,就不再一一做出聲明了。

程序員遷移模式

我想強調下最普遍的“終極節點”。在這些節點上,人們在他們所處的維度找不到更好的可替代編程語言。這些終極節點包括:Rust、 Java、 Go、 Python 3、Javascript 和 node.js(node.js 作為一種特殊的 Javascript,在這裡特別指出)。

幾年前,我認為 C 也是一個終極節點。可能現在也還可以這樣認為,因為有大量的重要項目(如 OS 內核)仍使用了 C,而且可以認為它無可替代。不過有跡象表明 C 其實是可以替代的。我最喜歡的例子就是有趣的空指針。Linux 內核有個編譯器帶來的致命弱點,即 NULL 值“不可能”出現,因此沒有對函數進行空指針檢查。C 也是一團糟,其規格裡有幾個新編程語言所沒有的致命錯誤。也許某天這些錯誤能被修複。

讓我們回退幾步。如果從頂部開始,根據人們進入編程的不同規格,可以看到四個主乾:

“低級”編程,包括 asm 和 C。

“商業型”或“學習型”編程,從 BASIC 開始。

計算類 / 科技類編程,如 Fortran,MATLAB 和 R。

腳本 / 膠水編程,如 shell 和 perl。

(我們也會談到“數據庫查詢語言”,比如 SQL。它是一枝獨秀,所有替代它的嘗試都以失敗告終。數據庫語言從上世紀六十年代開始就停滯不前了。甚至到現在,其關鍵字仍使用大寫,因為(他們認為)這樣能更好的理解代碼。)

(我還忽略了 HTML 和 CSS。他們是真正的語言,不過現在大家都開始學習這兩種語言,圖上無法用相應的箭頭來標識。Lisp 也沒有考慮在內,因為它一直沒有流行過,雖然有一小部分人一直希望它能流行起來。我還建議添加第五個分類,“配置編輯”)

(該圖也忽略了 Haskell。它可以在旁邊用一個獨立的框來表示,和其他語言之間沒有出入的箭頭,不過這沒關係。Haskell 是個自嘲式的大笑話,除非涉及到 Monads,它不再使用 I/O 概念。)

不管怎麽樣,讓我們回到上世紀九十年代。假設那時編程世界很簡單,(1) 初級程序員使用 C,asm 或者 Turbo Pascal,(2) 商業程序員使用 VB,(3) 數值計算人員使用 Fortran,R 或 MATLAB,(4) 膠水編程者使用 sh 或 perl。

那時,編程語言就是這麽嚴格劃分的。畫該圖時,我才意識到這一點。顯然,我們不會用 perl 來寫作業系統內核,不會用 MATLAB 來寫膠水程序,不會用 VB 來寫大型矩陣相乘算法。

現在則變化很大。選擇什麽樣的語言已經不再像過去那樣明確了。

語言的變化主要是風格的變化

我們先來看樹起點 asm(匯編語言)。用 Asm 來寫程序是相當困難的。不過即使到現在,它仍是寫某些程序最好的方式(如電腦啟動後的最初幾個指令,或是中斷處理的入口代碼)。不管是在 App Store 裡還是手機上的 JIT 裡,每個編譯語言最終都會將代碼編譯成匯編或機器語言。

基於 asm,出現了兩個分支:C 類型分支和 Pacal 類型分支。(Algol 出現的更早,不過此處忽略掉。宣稱自己是 Algol 程序員的人並不多。Algol 對其他語言影響很大。)

Pascal 風格分支語言的特點是有 "begin…end"。C 風格語言的特點則是有括號。當然,C 影響了很多的編程語言設計,這點在圖中沒有體現。因為我們現在討論的是程序員,而不是語言設計人員。

首先來看看 C。很奇怪,一旦人們開始使用 C,就習慣用它來處理各種情況。不管實現優劣與否,它是為數不多的能合理實現所有四類編程問題的語言之一。這四類都有些難度(除了低級編程,它正是 C 擅長的領域),不過 C 都能搞定,速度也還可以。

如果你是個 C 程序員,接下來會使用那種語言呢?這取決於用它來做什麽。

顯然,C++ 是一個選擇。雖然其名字與語法和 C 很像,但它其實和 C 風格迥異。除了 BeOS,其他作業系統內核不會使用 C++。在極具潛力的 Rust 使用前,作業系統基本都使用 C 編寫。

但是商業(“大型程序”)和數值計算(“快速程序”)領域的人員喜歡 C++。說喜歡不一定準確,但他們別無選擇,只能使用 C++。

對於膠水程序,很多人會直接從 C(或 C++)轉到 python 2。我最近也這樣做過。和怪異的 perl 不同,Python 2 類似 C 語言風格,其語法更簡單。C 程序員很容易理解 python C 模塊(並可以編寫新的 python 模塊)。從 python 裡調用 C 函數比其他語言更簡單。如果在 Java 裡調用,就需要處理非引用計數的垃圾回收問題。python 的“os”模塊提供了 C 系統調用及該調用能工作的環境。程序員可以訪問 C 語言中的錯誤碼並設置相應信號處理程序。唯一的問題就是 python 有些慢。不過隻把它作為膠水語言,則可以不考慮 python 的慢速。速度慢時,可以寫 C 模塊或調用 C 的庫或子程序。

另外,Java 面世後,很多 C 和 C++ 商業軟體的程序員非常快地切換到 Java。C++ 編譯時間長,頭文件繁多,可移植性差,有釋放後重用的錯誤問題。因此,雖然 Java 運行的很慢(和 python 不同的是,Java 宣稱“理論上運行很快”),人們還是更願意使用 Java。

我記得有篇文章講過,Go 的設計者最開始認為 Go 可以和 Java 或 C++ 媲美,但實際沒有做到。Java 就像知名酒店,或是門洛帕克(Menlo Park),一旦入住就不想離店。同時,程序員沒有從 C++ 切換到 Java 主要是因為:a)Java 速度比 C++ 慢,b)Java 仍有垃圾回收的經典問題。

Go 在之前已經切換到 python 2 的膠水程序人員中流行起來。事實證明 python 的慢速是其痛點所在。計算機複雜度急劇增加,python 膠水程序規模也越來越大。相較其優勢,動態類型帶來的麻煩更多,因此人們開始使用預編譯二進製。python 2 佔用很多記憶體,因此 Go 做了 RAM 改進,避免了從 C++ 遷移到 Go 帶來的問題。Go 的難度和 python 差不多,但它運行更快,佔用 RAM 更少。

我們現在稱 Go 是一種“系統”語言,因為提起膠水程序,我們更多的是想到 perl 和 ruby,不過它們的作用是一樣的。(試試告訴一個 C 語言內核開發者,Go 是“系統”語言,看看他們的反應)Go 是粘合劑,可以把各個組件組合到一起成為一個系統。

Hejlsberg 因素

我們接下來看 Visual Basic 和 Pascal 分支。人們有不同的想法:明顯正確的(“我為什麽會使用與 C 或 Java 一樣讓人痛苦的語言呢?”),或明顯錯誤的(“可視化的…Basic?開玩笑吧?”)。二十世紀八十年代和九十年代,一些人仍認為編程應該讓新手可以方便使用,因此在個人電腦上預裝了免費的編程語言,大部分都是 BASIC。

另一方面,大學教授編程時,則避開了 BASIC(“如果學生前期使用過 BASIC,就不能對學生很好的進行編程授課”),也沒有選擇 C。他們更傾向於 Pascal,認為 Pascal 易於學習。就像 Algol 的學術論文裡提到的一樣,而且它的語法適合教學,能讓每個學生都能聽懂。因此就有了學術分支和個人電腦分支,不過它們有個共同點,那就是都和 C 不像。

基於 PC(DOS)的 BASIC 演變為基於 Windows 的 Visual Basic,這可能是 javascript 出現前使用最多、最受歡迎的編程語言。(現在,它仍是在 Excel 中使用的“宏”語言。目前有很多 Excel 的程序員,雖然他們並不認為自己是程序員。)

同時,Pascal 也在努力往 PC 轉。因為 Turbo Pascal 的出現,它變得流行起來,並一度成為最快的編譯器。在速度上,Pascal 的確沒有誇張。甚至有一些 C 程序員也喜歡用 Pascal,不是因為喜歡其類 C 的語法,而是因為它的速度很快。(Turbo C 也可以,但速度還不夠。它比其他 C 編譯器都快。)(大學裡,Pascal 學術性越來越強,後來演變成 Modula 和 Ada。如果不是美國軍方在其高可靠系統中採用了 Ada 語言,這個分支早該終結了。現在我們可以忽略 Ada。)

那時還有兩個“商業”開發分支:BASIC 和 Pascal 分支。Windows 問世後,出現了 Visual Basic。基於 DOS 的 Turbo Pascal 有點過時,基於 WIndows 的 Turbo Pascal 也並不出眾。為了競爭,Turbo Pascal 的設計者 Anders Hejlsberg 創建了 Delphi。Delphi 和 Visual Basic 一樣,有可視化的編程環境,但它基於 Turbo Pascal 語言,也極少出現找不到或不匹配實時動態鏈接庫的煩人問題。

Delphi 很好,但它不屬於 Microsoft。摻雜商業因素後,局面變得有些困難。在一系列出人意料的事件之後,Hejlsberg 離開了 Microsoft,但仍繼續 C# 的開發,發布了 Microsoft .NET 平台,並包含 Visual Basic.Net (這是個很可怕的產品)。據稱 C# 統一了兩個分支。

不幸的是如前所述,VB.NET 很可怕。它和 Visual Basic 幾乎沒有共同點,更像是 C++ 的一個慢速版本,披了件有點非典型 Basic 的語法外衣,還帶著一個更糟的 UI 設計工具。C# 也不是 Delphi。不過這幾種語言都銷聲匿跡了,Microsoft 盡力推動了這一點。(除了 Microsoft Office,它到現在仍在使用最開始的 Visual Basic 語法,稱為 "Visual Basic for Applications", 即 VBA。比起.NET ,它使用的更廣泛,更受用戶喜歡。)

我不清楚怎樣才能叫做一名 Visual Basic 程序員。微軟致力於讓他們改用 VB.NET ,但大多數人並不願意。我想在圖中畫一條“他們實際的選擇”的箭頭,不過老實說我也不知道應該指向哪裡。也許他們成為了 web 開發者,或者編寫了 Excel 的宏。

從現在看,如果寫基於微軟主推的基於.NET 平台的 Windows 軟體,是件很有趣的事。可能使用的語言都會深受 Hejlsberg 的影響。Hejlsberg 的語言在反擊之前被微軟和 Visual Basic 所遏製,於是 Hejlsberg 轉向寫 Typescript,這個留待以後討論。

膠水語言的簡要介紹

最初的膠水語言是 Unix shell,它因引入“管道”概念也很著名。“管道”連接簡便的工具來完成複雜的工作。

啊,就是那些日子,那些日子一去不複返,perl 就是獻給它們的悼詞– Rob Pike

事實證明,設計小而簡單的工具是困難的,通常我們沒有足夠的時間來做這個。能夠讓我們跳過這些輕便工具,致力於編寫奇特的、能夠粘著很多亂七八糟的小程序的語言變得越來越流行。(它對 shell 語言的缺陷,尤其是與引用和通配符擴展規則相關的缺陷並沒有幫助。)

第一個是 awk,它是語法和 C 類似的解析語言,可以用在 shell 的管道上。那時,在一種語言(sh)的一行中裡使用另一種微語言(awk)有點奇怪,慶幸的是我們適應了,因為現在的 web 程序都是這樣的。(我們略過 csh,它是另一種與 C 語法不兼容的語言,存在不同的致命缺陷,可以被 sh 替代。)

接下來是 Perl。awk 沒有足夠多的標點符號,從而促成了 Perl 的產生。(好吧,這只是個玩笑。)

Perl 開始到 perl 5,越來越受歡迎。現在,Perl 停止改進語法,在 perl 6 上傾盡全力,從零開始打造。(在圖中並沒有標出 perl 6,因為還沒有人切換過去。)

這樣的配置給在幾個方向斷層進行“粘合”留下了空間。如果程序員覺得 perl 的語法差勁,可能會切換到 python。如果他們認為 perl 的語法很神奇有效力,只需要一些調整,則可能會切換到 ruby。如果使用 perl 來運行 web 的 CGI 腳本,則可能會保持原樣,也可能會轉而切換到 PHP。

ruby 很快成為 web 伺服器支持的語言(進而是 Ruby on Rails)。Python 也同樣在演進。

現在有趣的是:整整一代程序員摒棄了命令行方式(這也是膠水語言運行的方式),希望在 web 端可以做任何事情。從某方面來說,這樣更好,比如在一個膠水程序中可以超鏈接到另一個膠水程序。從另一方面來說,則更糟糕,因為現在所有的 web 程序都很慢,不能使用腳本,而且安裝 Electron 的另一個副本需要 500MB 的 RAM 空間等等。這就引入了 web 語言這個話題。

Web 語言

圖中,集中在 javascript 的“膠水”分支有很多的箭頭指向,這並不奇怪。Javascript 最初隻使用於前端。當 node.js 出現後,這種情況完全改變了。現在,只需要學習一種語言來寫前後端和命令行工具。Javascript 最初的設計是將其作為最終的膠水語言,試圖融合 HTML、CSS、面向對象編程、面向函數編程、動態語言、JITs 以及其它一切能通過 HTTP 請求得到的東西。

但是這樣不太好,因為後向兼容對於 web 的成功至關重要。要保證這一點,就無法修複一些嚴重錯誤。1995 年,經過 10 天的設計,Javascript 發布了。對於 10 天的成果而言,它相當優秀,但同時它也存在一些問題,無法對其進行修複。

這就是圖中唯一一個有雙向箭頭的地方:javascript 和 python 3 之間。我們把它叫做腳本語言的陰陽兩面。

大部分出現過的膠水 +web 語言正在消失,python 不在其列,至少目前還不會消失。我猜是因為 python 本身是合理的。使用 javascript 編程時間足夠長的話,過段段時間後就會變得不大正常。這時為了緩解壓力,程序員有可能會切換到 python。

同時,如果長時間使用 python,最後準備編寫 web 應用程序時,前端代碼和後端使用完全不同的語言是很煩人的。一個的語法是 [‘a’,‘b’,‘c’].join(’,’),而另一個則變成了’,’.join([‘a’,‘b’,‘c’]),這讓人完全記不清誰是誰了。

一種語言有 JIT,可以讓其一旦運行起來就會速度很快。而另一種則是啟動快,運行慢。

一種有合理的命名空間系統,而另一種則沒有。

我不清楚從長期看,python 3 是否能打敗 javascript。但至少目前看,它不會被擊敗。

同時,對於編程事實分支從不滿意的 Hejlsberg,看到了 javascript 的很多問題,引入了 TypeScript。與此同時,微軟突然停止了對 Windows 應用程序的大力推進,開始大面積推廣 web 和開源。這意味著 Microsoft 第一次將其開發者推向 web 語言即 javascript。在此基礎上,他們有自己的 TypeScript,我覺得這是一種很好的語言。這個分支存在有數十年,開始和其分支融合,可能不久後會消失。

TypeScript 和 javascript 比,能勝出嗎?這是個有趣的問題,我也不知道。我以前賭 Hejlsberg 能贏,不過我一般容易賭輸。

Python 2 和 Python 3 的對比

綜上所述,我對 python 2 和 3 有了結論。它們很相似,但不盡相同。我認為,這是因為他們在整個程序員語言遷移圖中所處的位置不同。Python 2 開發者來自 C 和 perl 開發人員,希望編寫膠水代碼。Web 伺服器是後續添加的一個應用場景。我的意思是,python 2 出現後,web 程序變得流行起來,這並不出人意料。很多 python 2 的開發者轉到 Go 的開發,因為他們想寫的某些“系統膠水”代碼使用 Go 正合適。

Python 3 的開發者是從不同的語言切換而來的。事實證明,python 3 問世後,python 的使用得到很大的發展,不過新加入的人群和以前的人群有所不同。由於帶有模塊 SciPy 和 Tensorflow,從科學類和數值類處理轉過來的新程序員佔了其中很大的比例。老實說,在高吞吐量的數值處理中,Python 是一個相當怪異的選擇。但不論如何,這些庫的存在是我們選擇它的一個原因。我猜 python 的另一個優勢則是易於和 C 模塊集成。當然,python 3 本身就是網絡編程。

想要理解 python 2 和 3 的區別,只需看看其不同的字元串類型。Python 2 中,字元串是一組字節,因為作業系統、Unix 管道處理、網絡 socket 的處理均以字節為部門。對於系統程序而言,python 2 是膠水語言,其處理以字節為部門。

在 python 3 中,字元串是一組 unicode 碼。因為人們不擅長 unicode 碼的轉換,而和網絡互動時,都是以 unicode 為基礎。做科學數值計算的人不關心字元串,做網絡編程的人更關心 unicode,所以 python 3 使用 unicode。如果要用 python 3 來編寫系統程序,就會一直疲於 unicode 的轉換,即使最簡單的文件名也需要進行轉換。這也正是有其因,必有其果。

https://apenwarr.ca/log/20190318

點個在看少個 bug

獲得更多的PTT最新消息
按讚加入粉絲團