編程的未來

有一句話,我覺得對程序員是至理名言:編程未來的趨勢是庫,動態的腳本語言和虛擬機。這句話我一聽就覺得很對,可是對它的領會(尤其是後半句話)卻花了很久,現在也還在半路上。

我一直很喜歡C++的一個基本的設計思想,就是有些事情是語言該做的,更多的事情卻應該交給庫去實現。正是這種思想,使得C++可以應用於各種領域。語言應該給程序員足夠的自由,從最底到最高層,從最機器的層面到最貼近現實的層面,然後,用這種語言,我們再來寫庫,用於各專有的領域。C++成爲了工業標準,它寫成的庫可以被各種語言使用、綁定,它被用來寫各種語言。任何宣傳C++的沒落的言論都是窄視的,它沒有看到C++是今天的許多事情的一個基石。C++ 是靜態語言所達到的一種極致。

C++與C的兼容以及對其規範化的推動,現在看來是做得再聰明不過的一件事情。時至今日,許多庫依然用C 寫成。C的生命力是C++成功的最重要的基石。在領略C++的無數美妙之處的過程中,我曾經以爲C已經沒落了,後來卻在實踐和更多的對源碼(gcc和 Linux內核)的閱讀中重新意識到C的永不消逝的價值。看到C裏的OOP甚至 AOP的種種實現,正如看到SICP中用Scheme做的編譯器時一樣,我意識到,更輕小更簡單的語言,卻能允許人類智力的最完全的發揮,也在一定程度上明白了爲什麼Linus會說“C++ to C is lang cancer to lang”。很多C++裏的東西,現在看來都很語法糖衣。然而,它最可貴的價值之一就在於,用一種語言,使我們學會了OO、多態和泛型的思維,同時也提供了一種對這些思維的描述。C++是設計模式最好的描述語言,我看到許多書用Java這種先天不足的語言來描述設計模式,就覺得彆扭。

是的,我恨Java,這種感情與日俱增。雖然我一直都在關注和學習它的技術,包括EJB,Struts,Hibernate和Spring,並且《J2EE Development without EJB》一書使我對這門語言背後的技術有了更大的好感,再加上最近看到一篇文章尖銳地指出Java並不慢,但是,刨去了所有沒有根據的偏見,使我憎恨這門語言的核心理由卻無法被撼動。不記得誰說過,Java是他第一次學習一門新語言沒有感到任何新的驚喜,沒有發現新的思想。我還要加上後半句:“反而感覺到一下子丟了好多東西”。Java使OO的一切都變得不再美妙,使一切變得麻煩,這就是我們爲所謂的簡化付出的代價。C++龐大而精深,任何一個怕難的人都可以棲居於這個語言的簡單部分,而讓寫庫的人去充分使用這個語言的其他層面。有了編寫良好的智能指針庫和對其恰當、適度的使用,所謂的用一種語言來 “把程序員從內存管理的泥潭中解放出來”就相當可笑。程序員的不自律和不善用庫沒有任何藉口。程序員之所以愛好編程,就是喜歡那種一切都可以做到,一切都可以掌控的感覺。靜態語言不能丟失指針,不能丟失引用,程序員不應該對const &厭煩。爲什麼除了棧我們還需要堆?在你離開作用域的時候,棧會嚴格地幫你回收利用你用過的東西,但你卻帶不走自己用過的東西。有了堆,你可以帶走了,你可以在應該回收的時候再放手。託管卻使你完全失去了對一切的控制力,你不得不把東西丟得滿地都是,等待機器人來撿你的餐巾。而且Java寫的程序就使用的時候感覺,也常有內存釋放的問題,也會崩潰。那麼,當初何必呢?靜態語言不應當放棄自己對內存的管理,自己束縛自己手腳。

Java 的流行的關鍵是,它對類庫的相對統一的捆綁,它的用虛擬機跨平臺,它的集成了多線程,它在Web方面和嵌入式方面採用的先進的技術和框架。這些構成了它的生命力,有人說它會消亡,那是不可能的。我不是看不到它的生命力,而是我一直寧可這些概念和技術是基於一門不那麼醜陋的語言,尤其不能容忍喝 Java咖啡的人不知天高地厚地恥笑C++,而且對那些把Java稱爲初戀的程序員感到極度噁心。我無法相信,發明Java的人會是真正資深的C++程序員,他們應該是在早年C++艱苦創業時受了苦的程序員。順便說一下,我相當明白爲什麼大家會把這些技術堆到Java身上,Java語言自身的簡易(從編譯實現的角度)和內存託管功不可沒。一切都是時機和真實的歷史進程惹的禍。

在看了D&E之後,我對Stroustrup相當佩服,我佩服他在各種程序員的口味面前堅持住了自己設計語言的哲學,保持了語言的純潔,使得C++的擴充並沒有使自己走形,這不是任何人能做到的。舉兩個我最欣賞的例子:純虛函數=0的語法,和後綴++重載的方式(operator++(int))。不過也可能有人對這個最不以爲然。講講我最喜歡C++的一些地方吧:儘量保持少的關鍵字,善用運算符,有運算符重載(可惜還不夠充分自由,要是有自定義操作符的功能就好了),有同名函數重載,有枚舉,精心設計的構造和析構體系(就像棧一樣讓人放心),類的定義和實現分離,模板以及相應的泛型編程,有作用域的typedef以及traits技術,保留了強大的C預處理宏(學C++先要學會不用宏,然後學會善用宏,可惜define間較難相互利用),有指針和引用,有各種const,有名稱空間,進行強類型檢查卻又保有隱式類型轉換,有完全可以善用的多重繼承,有精心設計的虛函數多態體系以及可愛的->,很多東西交給了庫而不是捆綁入語言,這使得我們可以有較多選擇。這裏太多太多東西Java沒有了,而以上每一樣技術都是程序員的好朋友。C++自己的問題在於編譯器的實現還不夠完美。

應該說,沒有使用過多個庫/類庫(尤其是開源庫)的C++程序員不算C++程序員。各種通用用途或專有用途的庫對於程序員的成長是非常有幫助的,它會培養程序員搭建編程環境,靠文檔和例子迅速上手,用Hack解決各種Bug、移植性或依賴性問題,對庫進行定製的能力,這些可是保持程序員在不斷涌現的新技術面前屹立不倒的能力啊。由於庫通常有各種語言的綁定,庫也使程序員能迅速擺脫語言的束縛,只要有庫,程序員的能力就不受限制。剩下的就是人月神話的問題了。我一直都在涉獵各種類庫,他們的源代碼就如同經卷,如果有足夠的時間,好想像玄奘一樣坐下來汲取它們的精華。

在C++之前,(從小學起)我用過 Logo,GWBasic,C, VB。在C++之後,很少再有什麼語言能給我真正的驚喜,直到我大範圍接觸動態腳本語言。Bash是最初的關於腳本的驚喜,但現在看來,它太不腳本了,不夠動態。後來用過或學習過,彙編(x86,一點PowerPC,現在正在學MMIX), Make, LaTeX, Matlab, ActionScript, JavaScript, Lex/Yacc, CSS/XPath, XML/JSON/YAML, Grapghiz, Metapost,Scheme,Squiril,PHP,Python,Ruby,Lua,Erlang 等語言,應該說各色語法都見過了,都有一段使用的時間,有些比較鍾愛的語言還是在多個時期分別使用過,有反覆的咀嚼和重新發現。

最近一段時間做了個網站(DHTML/CSS+LAMP+Ajax),加上對Prototype源代碼的閱讀,使得我對JavaScript有了重新的發現,同期的Ruby學習也令我驚喜不斷,我向所有人推薦這兩門語言,這兩門動態語言,最適合打破C++給程序員的靜態思維,PHP也不錯,除了用它做網站後端,用來做零活也不錯。相比之下,我還是不那麼喜歡Python,有待將來重新發現它了。JavaScript對於函數的內部變量的處理方式(掛爲函數的一個屬性)和把函數當做普通變量的做法,使得它的函數既能當Lamda函數用,又能當(一個可以不斷擴展的)類用,甚至可以當包用,相當偉大的設計。 JavaScript甚至發展出JSON作爲數據共享格式,比XML好多了,我相信它將在分佈式應用中發揮相當重要的角色。JavaScript和 Java根本是兩種完全不同的語言,完全不同的兩種思維範式,我從前對它有太多誤解。由於JavaScript和C很像,所以掌握其使用不難,但Ruby 則將要求你習慣另外一種思考問題和書寫語句的方式。Ruby中的迭代器是它最大的亮點之一,它對前一語句的返回值與{}塊進行了相當具有啓發性的使用。另外一個特別需要適應的思維是,這裏沒有強類型檢查,只有duck-typing,即如果我們只需要一個對象像鴨子一樣叫,只要這個對象能夠像鴨子一樣叫,我們就接受它是鴨子,不管它事實上是什麼。我原先對動態語言的無類型一直不適應,這次使用時才充分意識到它的威力。Ruby很有更多美妙的地方,這裏就不提了。

若干年前,有書推薦說,學了C/C++後,Java是相當合適的第二門語言。現在才知道大錯特錯。程序員的第二門語言應該是一門腳本語言,用來快速完成一些零活,也用於使程序員的思維靈活化。腳本語言的設計思路絕不能像靜態語言一樣,讓語言更純粹,事情讓庫做。腳本語言要內嵌許多常用的功能,不僅是通過核心庫來提供這些功能,更是要在語言層面支持更方便的調用。正則表達式就是其中最起碼的一個,數據庫的訪問、多線程也是相當重要的(且看Ruby的mutex.synchronize{})。

動態語言還有一個妙處在於eval(),我們可以動態地用腳本生成腳本的字符串,然後執行,這也是Bash當初令我驚喜的原因之一。自然,可以像訪問一個關聯數組一樣訪問創建過的變量、函數、類和Symbol,更是動態語言給程序員的最大自由。這兩個功能,前者使我們能使用使用語言構築的語言,後者使我們能夠進入語言的元層面。前者建起來,後者挖下去。這樣我們得以超出語言提供給我們的單一平面,有了第三個維度。

在文章的最後,簡單地說說虛擬機吧。

從使用VMWare在各平臺上調試程序,到使用各種模擬器玩遊戲,再到使用模擬器進行嵌入式開發,虛擬機的重要性不言而喻。始終希望Fusion或者seamless的技術能夠發展得更成熟——有了這種技術,我們可以在一個操作系統上無縫地使用另外一個操作系統上的程序。我可以裝個真正的雙系統,以其中一個操作系統爲主操作系統,需要時不用重啓可以調用另外一個操作系統中的程序,最關鍵的,是這個程序的運行環境,是真正基於那另外一個操作系統的,這樣不會有Wine的尷尬,不會有VM的慢。在多核的情況下,可以有多個操作系統來分別使用一個核。這樣的技術是可以實現的!只是還沒有。如果有足夠的內存,這樣的技術就可以足速運行。現在的情況是,軟件的開發跟不上硬件的發展,即使具備了相應的計算能力,卻不能享受到這種便利。一種可能的設想是,不要把虛擬機建在應用層或者內核層之上,而是在內核下面,在BIOS和Booter之間,並像VMWare Tools一樣,在應用層也有呼應,兩相配合。Intel和AMD已經在CPU裏對虛擬機做了支持,然而就使用它的KVM的性能表現來看,我還是比較失望的,可能是我沒有恰當使用,或者KVM還在剛起步的發展階段吧。還有Knuth的結合了各種計算機架構優勢的MMIX芯片,目前還只有虛擬機,我希望這樣的虛擬機能夠硬件化,然而這樣的事情,卻要等待真實的歷史進程了。

然而其實那句話所說的虛擬機,應該不是指這種虛擬機,而是指語言實現用的虛擬機。Chrome所用的JavaScript引擎V8,以及Mozilla的SpiderMonkey引擎,它們也是一種虛擬機,然而是屬於動態語言的虛擬機,解釋語言的虛擬機。這又涉及到自動狀態機……對這些方面瞭解不多,就此打住吧。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章