我的上一篇博文《與 C 語(yǔ)言長(zhǎng)別離》引來(lái)了我的老朋友,一位 C++ 專(zhuān)家的評(píng)論。在評(píng)論里,他推薦把 C++ 作為 C 的替代品。這是不可能發(fā)生的,如果 C++ 代替 C 是趨勢(shì)的話,那么 Go 和 Rust 也就不會(huì)出現(xiàn)了。
但是我不能只給我的讀者一個(gè)光禿禿的看法(LCTT 譯注:此處是雙關(guān)語(yǔ))。所以,在這篇文章中,我來(lái)講述一下為什么我不再碰 C++ 的故事。這是關(guān)于計(jì)算機(jī)語(yǔ)言設(shè)計(jì)經(jīng)濟(jì)學(xué)專(zhuān)題文章的起始點(diǎn)。這篇文章會(huì)討論為什么一些真心不好的決策會(huì)被做出來(lái),然后進(jìn)入語(yǔ)言的基礎(chǔ)設(shè)計(jì)之中,以及我們?cè)撊绾涡拚@些問(wèn)題。
在這篇文章中,我會(huì)一點(diǎn)一點(diǎn)的指出人們(當(dāng)然也包括我)自從 20 世紀(jì) 80 年代以來(lái)就存在的關(guān)于未來(lái)的編程語(yǔ)言的預(yù)見(jiàn)失誤。直到最近,我們才找到了證明我們錯(cuò)了的證據(jù)。
我記得我第一次學(xué)習(xí) C++ 是因?yàn)槲倚枰褂?GNU eqn 輸出 MathXML,而 eqn 是使用 C++ 寫(xiě)的。那個(gè)項(xiàng)目不錯(cuò)。在那之后,21 世紀(jì)初,我在韋諾之戰(zhàn)Battle For Wesnoth那邊當(dāng)了多年的資深開(kāi)發(fā)人生,并且與 C++ 相處甚歡。
在那之后啊,有一天我們發(fā)現(xiàn)一個(gè)不小心被我們授予提交權(quán)限的人已經(jīng)把游戲的 AI 核心搞崩掉了。顯然,在團(tuán)隊(duì)中只有我是不那么害怕查看代碼的。最終,我把一切都恢復(fù)正常了 —— 我折騰了整整兩周。再那之后,我就發(fā)誓我再也不靠近 C++ 了。
在那次經(jīng)歷過(guò)后,我發(fā)現(xiàn)這個(gè)語(yǔ)言的問(wèn)題就是它在嘗試使得本來(lái)就復(fù)雜的東西更加復(fù)雜,來(lái)粗陋補(bǔ)上因?yàn)榛A(chǔ)概念的缺失造成的漏洞。對(duì)于裸指針這樣?xùn)|西,它說(shuō)“別這樣做”,這沒(méi)有問(wèn)題。對(duì)于小規(guī)模的個(gè)人項(xiàng)目(比如我的魔改版 eqn),遵守這些規(guī)定沒(méi)有問(wèn)題。
但是對(duì)于大型項(xiàng)目,或者開(kāi)發(fā)者水平參差不齊的多人項(xiàng)目(這是我經(jīng)常要處理的情況)就不能這樣。隨著時(shí)間的推移以及代碼行數(shù)的增加,有的人就會(huì)捅簍子。當(dāng)別人指出有 BUG 時(shí),因?yàn)橹T如 STL 之類(lèi)的東西給你增加了一層復(fù)雜度,你處理這種問(wèn)題所需要的精力就比處理同等規(guī)模的 C 語(yǔ)言的問(wèn)題就要難上很多。我在韋諾之戰(zhàn)時(shí),我就知道了,處理這種問(wèn)題真的相當(dāng)棘手。
我給 Stell Heller(我的老朋友,C++ 的支持者)寫(xiě)代碼時(shí)不會(huì)發(fā)生的問(wèn)題在我與非 Heller 們合作時(shí)就被放大了,我和他們合作的結(jié)局可能就是我得給他們擦屁股。所以我就不用 C++ ,我覺(jué)得不值得為了其花時(shí)間。 C 是有缺陷的,但是 C 有 C++ 沒(méi)有的優(yōu)點(diǎn) —— 如果你能在腦內(nèi)模擬出硬件,那么你就能很簡(jiǎn)單的看出程序是怎么運(yùn)行的。如果 C++ 真的能解決 C 的問(wèn)題(也就是說(shuō),C++ 是類(lèi)型安全以及內(nèi)存安全的),那么失去其透明性也是值得的。但是,C++ 并沒(méi)有這樣。
我們判斷 C++ 做的還不夠的方法之一是想象一個(gè) C++ 已經(jīng)搞得不錯(cuò)的世界。在那個(gè)世界里,老舊的 C 語(yǔ)言項(xiàng)目會(huì)被遷移到 C++ 上來(lái)。主流的操作系統(tǒng)內(nèi)核會(huì)是 C++ 寫(xiě)就,而現(xiàn)存的內(nèi)核實(shí)現(xiàn),比如 Linux 會(huì)漸漸升級(jí)成那樣。在現(xiàn)實(shí)世界,這些都沒(méi)有發(fā)生。C++ 不僅沒(méi)有打消語(yǔ)言設(shè)計(jì)者設(shè)想像 D、Go 以及 Rust 那樣的新語(yǔ)言的想法,它甚至都沒(méi)有取代它的前輩。不改變 C++ 的核心思想,它就沒(méi)有未來(lái),也因此,C++ 的抽象泄露leaky abstraction也不會(huì)消失。
既然我剛剛提到了 D 語(yǔ)言,那我就說(shuō)說(shuō)為什么我不把 D 視為一個(gè)夠格的 C 語(yǔ)言競(jìng)爭(zhēng)者的原因吧。盡管它比 Rust 早出現(xiàn)了八年(和 Rust 相比是九年)Walter Bright 早在那時(shí)就有了構(gòu)建那樣一個(gè)語(yǔ)言的想法。但是在 2001 年,以 Python 和 Perl 為首的語(yǔ)言的出現(xiàn)已經(jīng)確定了,專(zhuān)有語(yǔ)言能和開(kāi)源語(yǔ)言抗衡的時(shí)代已經(jīng)過(guò)去。官方 D 語(yǔ)言庫(kù)/運(yùn)行時(shí)和 Tangle 的無(wú)謂紛爭(zhēng)也打擊了其發(fā)展。它從未修正這些錯(cuò)誤。
然后就是 Go 語(yǔ)言(我本來(lái)想說(shuō)“以及 Rust”。但是如前文所述,我認(rèn)為 Rust 還需要幾年時(shí)間才能有競(jìng)爭(zhēng)力)。它的確是類(lèi)型安全以及內(nèi)存安全的(好吧,是在大多數(shù)時(shí)候是這樣,但是如果你要使用接口的話就不是如此了,但是自找麻煩可不是正常人的做法)。我的一位好友,Mark Atwood,曾指出過(guò) Go 語(yǔ)言是脾氣暴躁的老頭子因?yàn)閼嵟鴦?chuàng)造出的語(yǔ)言,主要是C 語(yǔ)言的作者之一(Ken Thompson) 因?yàn)?C++ 的混亂臃腫造成的憤怒,我深以為然。
我能理解 Ken 惱火的原因。這幾十年來(lái)我就一直認(rèn)為 C++ 搞錯(cuò)了需要解決的問(wèn)題。C 語(yǔ)言的后繼者有兩條路可走。其一就是 C++ 那樣,接受 C 的抽象泄漏、裸指針等等,以保證兼容性。然后以此為基礎(chǔ),構(gòu)建一個(gè)最先進(jìn)的語(yǔ)言。還有一條道路,就是從根源上解決問(wèn)題 ——修正C語(yǔ)言的抽象泄露。這一來(lái)就會(huì)破環(huán)其兼容性,但是也會(huì)杜絕 C/C++ 現(xiàn)有的問(wèn)題。
對(duì)于第二條道路,第一次嚴(yán)謹(jǐn)?shù)膰L試就是 1995 年出現(xiàn)的 Java。Java 搞得不錯(cuò),但是在語(yǔ)言解釋器上構(gòu)建這門(mén)語(yǔ)言使其不適合系統(tǒng)編程。這就在系統(tǒng)編程那留下一個(gè)巨大的洞,在 Go 以及 Rust 出現(xiàn)之前的 15 年里,都沒(méi)有語(yǔ)言來(lái)填補(bǔ)這個(gè)空白。這也就是我的 GPSD 和 NTPsec 等軟件在 2017 年仍然主要用 C 寫(xiě)成的原因,盡管 C 的問(wèn)題也很多。
在許多方面這都是很糟糕的情況。盡管由于缺少足夠多樣化的選擇,我們很難認(rèn)識(shí)到 C/C++ 做的不夠好的地方。我們都認(rèn)為在軟件里面出現(xiàn)缺陷以及基于安全方面考慮的妥協(xié)是理所當(dāng)然的,而不是想想這其中多少是真的由于語(yǔ)言的設(shè)計(jì)問(wèn)題導(dǎo)致的,就像緩存區(qū)溢出漏洞一樣。
所以,為什么我們花了這么長(zhǎng)時(shí)間才開(kāi)始解決這個(gè)問(wèn)題?從 C 1972 年面世到 Go 2009 年出現(xiàn),這其中隔了 37 年;Rust 也是在其僅僅一年之前出現(xiàn)。我想根本原因還是經(jīng)濟(jì)。
從最早的計(jì)算機(jī)語(yǔ)言開(kāi)始,人們就已經(jīng)知道,每種語(yǔ)言的設(shè)計(jì)都體現(xiàn)了程序員時(shí)間與機(jī)器資源的相對(duì)價(jià)值的權(quán)衡。在機(jī)器這端,就是匯編語(yǔ)言,以及之后的 C 語(yǔ)言,這些語(yǔ)言以犧牲開(kāi)發(fā)人員的時(shí)間為代價(jià)來(lái)提高性能。 另一方面,像 Lisp 和(之后的)Python 這樣的語(yǔ)言則試圖自動(dòng)處理盡可能多的細(xì)節(jié),但這是以犧牲機(jī)器性能為代價(jià)的。
廣義地說(shuō),這兩端的語(yǔ)言的最重要的區(qū)別就是有沒(méi)有自動(dòng)內(nèi)存管理。這與經(jīng)驗(yàn)一致,內(nèi)存管理缺陷是以機(jī)器為中心的語(yǔ)言中最常見(jiàn)的一類(lèi)缺陷,程序員需要手動(dòng)管理資源。
當(dāng)相對(duì)價(jià)值斷言與軟件開(kāi)發(fā)在某個(gè)特定領(lǐng)域的實(shí)際成本動(dòng)因相匹配時(shí),這個(gè)語(yǔ)言就是在經(jīng)濟(jì)上可行的。語(yǔ)言設(shè)計(jì)者通過(guò)設(shè)計(jì)一個(gè)適合處理現(xiàn)在或者不遠(yuǎn)的將來(lái)出現(xiàn)的情況的語(yǔ)言,而不是使用現(xiàn)有的語(yǔ)言來(lái)解決他們遇到的問(wèn)題。
隨著時(shí)間的推移,時(shí)興的編程語(yǔ)言已經(jīng)漸漸從需要手動(dòng)管理內(nèi)存的語(yǔ)言變?yōu)閹в凶詣?dòng)內(nèi)存管理以及垃圾回收(GC)機(jī)制的語(yǔ)言。這種變化對(duì)應(yīng)了摩爾定律導(dǎo)致的計(jì)算機(jī)硬件成本的降低,使得程序員的時(shí)間與之前相比更加的寶貴。但是,除了程序員的時(shí)間以及機(jī)器效率的變化之外,至少還有兩個(gè)維度與這種變化相關(guān)。
其一就是距離底層硬件的距離。底層軟件(內(nèi)核與服務(wù)代碼)的低效率會(huì)被成倍地?cái)U(kuò)大。因此我們可以發(fā)現(xiàn),以機(jī)器為中心的語(yǔ)言向底層推進(jìn),而以程序員為中心的語(yǔ)言向著高級(jí)發(fā)展。因?yàn)榇蠖鄶?shù)情況下面向用戶(hù)的語(yǔ)言?xún)H僅需要以人類(lèi)的反應(yīng)速度(0.1 秒)做出回應(yīng)即可。
另一個(gè)維度就是項(xiàng)目的規(guī)模。由于程序員抽象發(fā)生的問(wèn)題的漏洞以及自身的疏忽,任何語(yǔ)言都會(huì)有可預(yù)期的每千行代碼的出錯(cuò)率。這個(gè)比率在以機(jī)器為中心的語(yǔ)言上很高,而在程序員為中心的帶有 GC 的語(yǔ)言里就大大降低。隨著項(xiàng)目規(guī)模的增大,帶有 GC 的語(yǔ)言作為一個(gè)防止出錯(cuò)率不堪入目的策略就顯得愈發(fā)重要起來(lái)。
當(dāng)我們使用這三種維度來(lái)看當(dāng)今的編程語(yǔ)言的形勢(shì) —— C 語(yǔ)言在底層,蓬勃發(fā)展的帶有 GC 的語(yǔ)言在上層,我們會(huì)發(fā)現(xiàn)這基本上很合理。但是還有一些看似不合理的是 —— C 語(yǔ)言的應(yīng)用不合理地廣泛。
我為什么這么說(shuō)?想想那些經(jīng)典的 Unix 命令行工具吧。那些小程序通常都可以使用帶有完整的 POSIX 支持的腳本語(yǔ)言快速實(shí)現(xiàn)出來(lái)。重新編碼那些程序?qū)⑹沟盟鼈冋{(diào)試、維護(hù)和拓展起來(lái)都會(huì)更加簡(jiǎn)單。
但是為什么還是使用 C (或者某些像 eqn 的項(xiàng)目,使用 C++)?因?yàn)橛修D(zhuǎn)換成本。就算是把相當(dāng)小、相當(dāng)簡(jiǎn)單的程序使用新的語(yǔ)言重寫(xiě)并且確認(rèn)你已經(jīng)忠實(shí)地保留了所有非錯(cuò)誤行為都是相當(dāng)困難的。籠統(tǒng)地說(shuō),在任何一個(gè)領(lǐng)域的應(yīng)用編程或者系統(tǒng)編程在一種語(yǔ)言的權(quán)衡過(guò)時(shí)之后,仍然堅(jiān)持使用它。
這就是我和其他預(yù)測(cè)者犯的大錯(cuò)。 我們認(rèn)為,降低機(jī)器資源成本(增加程序員時(shí)間的相對(duì)成本)本身就足以取代 C 語(yǔ)言(以及沒(méi)有 GC 的語(yǔ)言)。 在這個(gè)過(guò)程中,我們有一部分或者甚至一大部分都是錯(cuò)誤的 —— 自 20 世紀(jì) 90 年代初以來(lái),腳本語(yǔ)言、Java 以及像 Node.js 這樣的東西的興起顯然都是這樣興起的。
但是,競(jìng)爭(zhēng)系統(tǒng)編程語(yǔ)言的新浪潮并非如此。 Rust 和 Go 都明確地回應(yīng)了增加項(xiàng)目規(guī)模這一需求。 腳本語(yǔ)言是先是作為編寫(xiě)小程序的有效途徑,并逐漸擴(kuò)大規(guī)模,而 Rust 和 Go 從一開(kāi)始就定位為減少大型項(xiàng)目中的缺陷率。 比如 Google 的搜索服務(wù)和 Facebook 的實(shí)時(shí)聊天復(fù)用。
我認(rèn)為這就是對(duì) “為什么不再早點(diǎn)兒” 這個(gè)問(wèn)題的回答。Rust 和 Go 實(shí)際上并不算晚,它們相對(duì)迅速地回應(yīng)了一個(gè)直到最近才被發(fā)現(xiàn)低估的成本動(dòng)因問(wèn)題。
好,說(shuō)了這么多理論上的問(wèn)題。按照這些理論我們能預(yù)言什么?它告訴我們?cè)?C 之后會(huì)出現(xiàn)什么?
推動(dòng) GC 語(yǔ)言發(fā)展的趨勢(shì)還沒(méi)有扭轉(zhuǎn),也不要期待其扭轉(zhuǎn)。這是大勢(shì)所趨。因此:最終我們將擁有具有足夠低延遲的 GC 技術(shù),可用于內(nèi)核和底層固件,這些技術(shù)將以語(yǔ)言實(shí)現(xiàn)方式被提供。 這些才是真正結(jié)束 C 長(zhǎng)期統(tǒng)治的語(yǔ)言應(yīng)有的特性。
我們能從 Go 語(yǔ)言開(kāi)發(fā)團(tuán)隊(duì)的工作文件中發(fā)現(xiàn)端倪,他們正朝著這個(gè)方向前進(jìn) —— 可參見(jiàn)關(guān)于并發(fā) GC 的學(xué)術(shù)研究 —— 從未停止研究。 如果 Go 語(yǔ)言自己沒(méi)有選擇這么做,其他的語(yǔ)言設(shè)計(jì)師也會(huì)這樣。 但我認(rèn)為他們會(huì)這么做 —— 谷歌推動(dòng)他們的項(xiàng)目的能力是顯而易見(jiàn)的(我們從 “Android 的發(fā)展”就能看出來(lái))。
在我們擁有那么理想的 GC 之前,我把能替換 C 語(yǔ)言的賭注押在 Go 語(yǔ)言上。因?yàn)槠?GC 的開(kāi)銷(xiāo)是可以接受的 —— 也就是說(shuō)不只是應(yīng)用,甚至是大部分內(nèi)核外的服務(wù)都可以使用。原因很簡(jiǎn)單: C 的出錯(cuò)率無(wú)藥可醫(yī),轉(zhuǎn)化成本還很高。
上周我嘗試將 C 語(yǔ)言項(xiàng)目轉(zhuǎn)化到 Go 語(yǔ)言上,我發(fā)現(xiàn)了兩件事。其一就是這活很簡(jiǎn)單, C 的語(yǔ)言和 Go 對(duì)應(yīng)的很好。還有就是寫(xiě)出的代碼相當(dāng)簡(jiǎn)單。由于 GC 的存在以及把集合視為首要的數(shù)據(jù)結(jié)構(gòu),人們會(huì)預(yù)期代碼減少,但是我意識(shí)到我寫(xiě)的代碼比我最初期望的減少的更多,比例約為 2:1 —— 和 C 轉(zhuǎn) Python 類(lèi)似。
抱歉吶,Rust 粉們。你們?cè)趦?nèi)核以及底層固件上有著美好的未來(lái),但是你們?cè)趧e的 C 領(lǐng)域被 Go 壓的很慘。沒(méi)有 GC ,再加上難以從 C 語(yǔ)言轉(zhuǎn)化過(guò)來(lái),還有就是 API 的標(biāo)準(zhǔn)部分還是不夠完善。(我的select(2)又哪去了啊?)。
對(duì)你們來(lái)說(shuō),唯一的安慰就是,C++ 粉比你們更糟糕 —— 如果這算是安慰的話。至少 Rust 還可以在 Go 顧及不到的 C 領(lǐng)域內(nèi)大展宏圖。C++ 可不能。
-
計(jì)算機(jī)
+關(guān)注
關(guān)注
19文章
7544瀏覽量
88656 -
C語(yǔ)言
+關(guān)注
關(guān)注
180文章
7614瀏覽量
137745 -
C++
+關(guān)注
關(guān)注
22文章
2114瀏覽量
73861
原文標(biāo)題:計(jì)算機(jī)語(yǔ)言的巨變
文章出處:【微信號(hào):LinuxHub,微信公眾號(hào):Linux愛(ài)好者】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
EBSD技術(shù)在氬離子截面切割制樣中的應(yīng)用
![EBSD技術(shù)在氬離子截面切割制樣中的應(yīng)用](https://file1.elecfans.com/web3/M00/04/F0/wKgZPGd7XBaAZuuUAACUyy1IyW4838.png)
光耦合器的演變:過(guò)去、現(xiàn)在和未來(lái)
關(guān)于永磁材料與永磁電機(jī),你了解多少?
功率半導(dǎo)體各品類(lèi)及下游應(yīng)用市場(chǎng)空間分析
![功率半導(dǎo)體各品類(lèi)及下游應(yīng)用市場(chǎng)空間分析](https://file.elecfans.com/web2/M00/40/03/pYYBAGJrSWqAb-nSAAAXmKtCFeo833.jpg)
【每天學(xué)點(diǎn)AI】五個(gè)階段帶你了解人工智能大模型發(fā)展史!
![【每天學(xué)點(diǎn)AI】五個(gè)階段帶你了解人工智能大模型發(fā)展史!](https://file1.elecfans.com/web2/M00/08/DE/wKgaombzzn6AA9kAAADAZn99ItA915.png)
光學(xué)識(shí)別技術(shù)的工作原理是什么?
國(guó)產(chǎn)工控機(jī)的發(fā)展與未來(lái)
![國(guó)產(chǎn)工控機(jī)的發(fā)展與<b class='flag-5'>未來(lái)</b>](https://file1.elecfans.com/web2/M00/02/11/wKgZoma53DuAPObpAACBUEB2dfE006.png)
圖像識(shí)別算法有哪幾種
自然語(yǔ)言處理技術(shù)的核心是什么
Keil這么難用,為什么還沒(méi)有被淘汰?
![Keil這么難用,為什么還沒(méi)有被淘汰?](https://file.elecfans.com/web2/M00/9B/3D/poYBAGQjnauAVXOgAABFcEbXdEE684.png)
電力二極管的定義 電力二極管動(dòng)態(tài)過(guò)程的波形介紹
![電力二極管的定義 電力二極管動(dòng)態(tài)過(guò)程的波形介紹](https://file1.elecfans.com/web2/M00/C5/CD/wKgZomYCdgWAVXfcAABrDsl9U3879.jpeg)
無(wú)人機(jī)科技:顛覆未來(lái)的空中變革之力
![無(wú)人機(jī)科技:顛覆<b class='flag-5'>未來(lái)</b>的空中變革之力](https://file1.elecfans.com/web2/M00/C2/4D/wKgZomXhleKAYHwDAABkWal87lM279.png)
什么是NTC熱敏電阻、原理及作用
![什么是NTC熱敏電阻、原理及作用](https://file1.elecfans.com/web2/M00/C2/F5/wKgaomXf3zmAC-YjAAAgaxDtu_s837.png)
評(píng)論