我的程序语言实践
動靜之間,不變的本質(zhì)
??????? ——我的程序語言實踐
===========
引子
====
源于SD2.0大會的召開,以及拙作《JavaScript語言精髓與編程實踐》一書的出版在即,CSDN、博文視點以及《程序員》的編輯都希望我寫一點關(guān)于語言的東西。我已經(jīng)為這個問題苦惱了很久,因為我不知道可以說什么,既可以與先行者有別,又可以使后來者為鑒。
這下便借用《程序設(shè)計語言實踐》一書的書名,講講我的經(jīng)歷吧。
從動態(tài)語言到靜態(tài)語言
====
我所學的第一門語言其實是數(shù)據(jù)庫編程語言DBASE,參加的是學校的一個暑期的關(guān)于微機操作的培訓——程序設(shè)計語言只是其中很小的一部分,我們得從鍵盤鍵位之類的開始學起。就這樣,我也只學了十天。這是在1994年,當時用的是DBASE III。DBASE是解釋執(zhí)行的、弱類型的一種語言,我用它寫過數(shù)據(jù)庫的前置的口令檢測程序。很快我就換成了BASIC,換這門語言的原因是當時要參加省賽區(qū)的一個競賽,我用了一個月略多的時間來學習它就參賽了,結(jié)果是第二名。在后來的學習中,我用BASIC寫過內(nèi)存處理、端口處理程序。到了1997年的時候,我的一個朋友的畢業(yè)設(shè)計要用BASIC來寫,當時我已經(jīng)丟下BASIC兩年了,但還是用了一晚的時間完成了一個考試管理系統(tǒng),包括班級、學科管理、成績管理和檔案管理(含磁盤檢測以上報檔案)。當時我用了一個名為Turbo Basic的東東,是Borland做的最后一款BASIC語言的工具,據(jù)內(nèi)幕說是因為與微軟存在協(xié)議,后來Borland再也沒出過這一語言的工具。
(*) 順便補充一點,那個微機培訓的課程是一個月,而我當時對文學感興趣,因為要去北京參加一個筆會而只學了十天。我對文學的興趣持續(xù)到1999年,在2000年的時候,一篇早期的文學作品拿了網(wǎng)易首屆網(wǎng)絡(luò)文學大屆的散文金獎(這個大賽也只辦了一屆,哈哈)。而對文字的喜好則持續(xù)到現(xiàn)在,成了我寫書作文的根基與動力。
在DOS時代還有一種可編程的批處理(當然現(xiàn)在在Windows系統(tǒng)中也有,只是用的人實在不多了),我曾經(jīng)用它與BASIC和匯編結(jié)合起來,寫過系統(tǒng)加鎖程序。這些大概都是在1996年之前的事了。
我學習編譯型語言的時間晚于解釋型的,最初是在1995年初開始自學《數(shù)據(jù)結(jié)構(gòu)》一書,那一版的書就是用PASCAL語法來講的,而我學算法語言晚于學《數(shù)據(jù)結(jié)構(gòu)》,所以當時并不會PASCAL,也不可能在當時的BASIC中理解這些復雜的數(shù)據(jù)結(jié)構(gòu)。因此我又買來Pascal語言入門教材自學,然而題不對板,數(shù)據(jù)結(jié)構(gòu)中用的與我這本書所講的,以及我能用的Pascal編譯器三者全不靠譜,而那時候我還在死學死用的層次上,學了半年而無有小成。
然而《數(shù)據(jù)結(jié)構(gòu)》卻沒有耽擱,對這門學科的學習成了我這么多年來理解編程的基礎(chǔ)。再后來,我又開始自學匯編語言、算法語言(Pascal)和操作系統(tǒng)原理,到了1996年初,我基本上已經(jīng)完成了對語言和系統(tǒng)的自學。這個時候,我的語言選擇已經(jīng)從Basic轉(zhuǎn)到了Pascal。
換言之,我從動態(tài)語言走到了靜態(tài)語言。不過這樣說,我可能被立即反問:它們是動態(tài)語言嗎?我慎之又慎的思考之后的回答,仍然“是”。前面提到的DBASE、BASIC和批處理其實都有動態(tài)語言的特征——盡管這在我學習它們時是不知的。
回歸動態(tài)-從Delphi到JavaScript
====
知道我的朋友很多是因為Delphi以及我所寫的《Delphi源代碼分析》一書。我從1996年開始做一些商業(yè)產(chǎn)品的代碼,一直到2003年都是使用的Pascal/Delphi系列語言,以及一些匯編語言。我從傳統(tǒng)過程式開發(fā)轉(zhuǎn)變到面向?qū)ο箝_發(fā),用了非常長的時間——超過兩年。直到2003年的早些時候,我終于停下忙忙碌碌的、無止盡的代碼書寫,問了自己一個問題:Delphi是怎么回事?
為了給自己解答這個問題,我辭掉所有的工作,靜下心來研究這門語言。準確地說,是研究靜態(tài)語言的語法、語義以及面向操作系統(tǒng)的編譯與二進制文件生成。《Delphi源代碼分析》這本書講的就樣的一些內(nèi)容:語言的基本要素、操作系統(tǒng)對語言的要求、語言的實現(xiàn)等等。只不過我是通過對Delphi的源代碼的分析來展現(xiàn)這些罷了。
用了一年的時間,我終于看明白語言在“結(jié)構(gòu)”方面的真相:所有的語言效果、語法以及二進制的執(zhí)行能力,原來不過是操作系統(tǒng)理解的一堆“可執(zhí)行和可存取的數(shù)據(jù)結(jié)構(gòu)”。“編譯”這一過程,無非是把這些細節(jié)隱藏起來,讓程序員以為自己在寫一種非常高級的、邏輯的、有趣的代碼,而忽視掉背后的本質(zhì)部分:靜態(tài)的數(shù)據(jù)與指令。
如同我此前對于Pascal/Delphi的盲目一樣,我學用JavaScript之初也是盲目的。我選擇JavaScript的唯一原因,只是因為我在Web上開發(fā)時找不到第二種可以通用的語言(如果當時我能選擇一種類pascal語法的語言,我一定會錯失學習JavaScript的良機)。
我從1998年開始使用JavaScript,這離這門語言被創(chuàng)生出來不過三年時間——以語言的歷史而言,這算得上是“追新”了。在最初我無非是把它當成一種腳本化的過程式語言,以及用來響應(yīng)網(wǎng)頁里的OnXXXX事件的一些代碼。但在一兩年之后,在我深受Delphi中的面向?qū)ο缶幊趟枷氲挠绊懼?#xff0c;我發(fā)現(xiàn)JavaScript令我不堪忍受:它畢竟不是一門具有完整的對象特性的語言。于是我開始試圖實現(xiàn)JSOOP:JavaScript的面向?qū)ο缶幊獭?/span>
這一設(shè)想以及一些實踐開始于2002年,但直到2004年初我才真正著手實施這個計劃,到了2005年末這個項目延伸為現(xiàn)在的Qomo(Qomolangma OpenProject)。而我另一方面的計劃——自2005年初開始寫的一本名為《B端開發(fā)》的書,也終于因為Qomo項目而被放棄,變成了《JavaScript語言精髓與編程實踐》。因為在Qomo開發(fā)過程中,我發(fā)現(xiàn)討論JavaScript這種語言本身,遠比“在瀏覽器端(B端)開發(fā)”更為有趣。盡管,在這其間我還用過PHP、Java與C#等等,不過相對于后面要討論的內(nèi)容來說,這些已經(jīng)不重要了。
因為我對編程的理解,終于從Delphi走回JavaScript,從靜態(tài)回歸到動態(tài)。
JavaScript語言的基本特性
====
到底JavaScript是怎樣的、以及為什么會吸引我呢?如今我之視見,JavaScript語言包括了四個方面的語言特性:過程式語言、面向?qū)ο笳Z言、函數(shù)式語言和動態(tài)語言。具有過程式特性,是它入門容易的原因;面向?qū)ο筇匦詣t使它符合主流的程序設(shè)計思想;函數(shù)式是JavaScript語言的根基,而動態(tài)語言則是它的外在表現(xiàn),以及強大到難于駕馭的根源。
前些時候在北京參與CSDN大會時,與一個老朋友談到JavaScript,他說:JavaScript具有幾乎所有主要語言形式的原子要素。我覺得,這個“語言原子”的概念就提得很好。的確,JavaScript在上述四個方面都表現(xiàn)平平,但每個方面都抓住了相應(yīng)語言范型的精髓。不但如此,JavaScript還使用了一個最簡而又最合理的方式來組織各種語言特性。僅以“動態(tài)”而論,《JavaScript語言精髓與編程實踐》講述了JavaScript所包括的四個方面的動態(tài)性質(zhì):
?- 動態(tài)執(zhí)行
?- 動態(tài)類型
?- 重寫
?- 實現(xiàn)動態(tài)環(huán)境的基礎(chǔ)數(shù)據(jù)結(jié)構(gòu)
源于本文篇幅,對于更深層面的問題便不討論了,這里僅討論一下靜態(tài)執(zhí)行與動態(tài)執(zhí)行的某些本質(zhì)上的差異。舉個例子來說,下面的代碼:
------
obj.aMethod(x,y,z);
------
這顯然是一個對象方法調(diào)用。但對象方法是如何實現(xiàn)的呢?在靜態(tài)語言中,因為有編譯過程,所以我們把一個結(jié)構(gòu)放在內(nèi)存里,并使得它
? - 擁有一個對象實例指針指向obj,
? - 擁有一個對象方法指針指向aMethod()在代碼區(qū)的地址,
? - 在有效代碼的前后加入處理x,y,z這些參數(shù)的代碼(例如入棧與清棧)。
在執(zhí)行時,我們將obj與aMethod交給執(zhí)行系統(tǒng),并傳入指定參數(shù)(的序列),然后就可以按照既已編譯的規(guī)則來執(zhí)行了。
------
isTrue ? expr1 : expr2
------
就被表達為
??????? root(?)
???????? /?? /?
left(isTrue)? right(:)
?????????????? /? /
?????? left(expr1) right(expr2) ——學過數(shù)據(jù)結(jié)構(gòu)的開發(fā)者一定對此不會陌生,因此我就不細講實現(xiàn)和使用這個結(jié)構(gòu)的過程了(其實三元表達式不能描述為這個結(jié)構(gòu),但這里只為了說明問題,請不要去追究它。)。不過這一結(jié)構(gòu)也顯然地可以陳述為一個lisp/scheme表達式。同樣的道理,一個對象方法的過程亦是如此,用這樣的方法來表達上面的“對象方法調(diào)用”,就可以用lisp/scheme方法來陳述:
------
((. obj aMethod) x y z)
------
正是這個細節(jié),表明在JavaSctipt中所謂的“對象方法調(diào)用”,其本質(zhì)上是函數(shù)式語言中的一個運算式。因其是一個運算式,所以能動態(tài)地(作為語法樹的一部分)解釋執(zhí)行。
同樣的方法,可以解構(gòu)所有在JavaScript有關(guān)執(zhí)行系統(tǒng)(語句、表達式、函數(shù)等)的問題,基本上都可以歸結(jié)到函數(shù)式這個范圍內(nèi)。換而言之:函數(shù)式這個“原子”為JavaScript提供了執(zhí)行和動態(tài)執(zhí)行能力。
再往后,我考察了JavaScript在數(shù)據(jù)結(jié)構(gòu)層面上的實現(xiàn)。這方面最精當(而又平凡)的解釋是前兩天在微軟架構(gòu)師有關(guān)語言的討論中做出的:JavaScript的對象其實是“屬性包”。不過,更專業(yè)而難解的詞匯是“關(guān)聯(lián)數(shù)組”。JavaScript使用關(guān)聯(lián)數(shù)組作為動態(tài)化類型的基礎(chǔ),而靜態(tài)的值類型僅包括布爾、數(shù)值、字符串類型(字符串兼具值與引用兩方面特性)和undefined四種。當所有的類型被歸結(jié)到這里時,就可以發(fā)現(xiàn)“動態(tài)”的另一層含義與”引用“結(jié)合了起來:
? - 所謂引用,不過是動態(tài)地找到值的一種手段
另一方面,對運算系統(tǒng)的考察,也會被歸結(jié)到這里:
? - 所謂運算,本質(zhì)是針對值的運算
舉個實例來說,例如:
------
aWindow.width = obj.aMethod(x,y,z);
------
其中".width”運算的目的是找到一個值類型的屬性;“.aMethod()”的目的是找到一個函數(shù)并調(diào)用它,然后返回某個值;“=”運算則將某值傳入某個存值的屬性。
所以,根源上來說,JavaScript中的所有運算都是圍繞“如何得到和使用值(類型)數(shù)據(jù)”來的。對此更深入的推論是:所有的計算系統(tǒng)都是圍繞這一根本目的來的。
在寫《JavaScript語言精髓與編程實踐》的過程中,我一次又一次地回顧了我對Delphi的所有理解,拋開那些將語法樹靜態(tài)化到內(nèi)存結(jié)構(gòu)和磁盤文件結(jié)構(gòu)的過程,我看到:所有靜態(tài)與動態(tài)語言,在本義上所追求的,無非是算法與結(jié)構(gòu)的平衡——即先滿足算法實現(xiàn)一致性,還是先滿足結(jié)構(gòu)實現(xiàn)一致性的問題。
在這十余年之中,我從動態(tài)開始,深入靜態(tài)又回歸動態(tài),最終我來到了原點:程序=算法+結(jié)構(gòu)。
學兩種語言
====
在《程序設(shè)計語言實踐》中對“語言”有一個分類法,將語言分類為“說明式”與“命令式”兩種。Delphi以及C、C++、Java、C#等都被分為“命令式”語言范型的范疇;“函數(shù)式”語言則是“說明式”范型中的一種。我如今回顧我對語言的學習,其實十年也就學會了兩門語言:一門是命令式的,一門是說明式的。當然從語言的實現(xiàn)方式來看,一門是靜態(tài)的,一門是動態(tài)的。
這便是我程序員生涯的全部了。
我畢竟不是計算機科學的研究者,而只是其應(yīng)用的實踐者,因而我從一開始就缺乏對“程序”的某些科學的或?qū)W術(shù)層面上的認識是很正常的。也許有些人認為一開始程序便是如此,或者一門語言就應(yīng)當是這樣構(gòu)成和實現(xiàn)的,那么可能他是從計算機科學走向應(yīng)用,故而比我了解得多些。而我,大概在十年前學習編程,以及在后來很多年的實踐中,僅被要求“寫出代碼”,而從未被要求了解“什么是語言”。所以我才會后知后覺,才會在很長的時間里迷失于那些精細的、溝壑縱橫的語言表面而不自知。然而一如我現(xiàn)在所見到,與我曾相同地行進于那些溝壑的朋友,仍然在持續(xù)地迷惑著、盲目著,全然無覺于溝壑之外的瑰麗與宏偉。
前些天寫過一篇BLOG,是推薦那篇“十年學會編程”的。那篇文章道出了我在十年編程實踐之后,對程序語言的最深刻的感概。我們學習語言其實不必太多,深入一兩種就可以了。如果在一種類型的語言上翻來覆去,例如學C、Delphi、Java、C#……無非是求生存、討生活,或者用以裝點個人簡歷,于編程能力上提高是不大的。更多的人,因為面臨太多的語言選擇而淺嘗轍止,多年之后仍遠離程序根本,成為書寫代碼的機器,把書寫代碼的行數(shù)、程序個數(shù)或編程年限作為簡歷中最顯要的部分。這在明眼人看來,無過是熟練的磚頭工而已。
《大道至簡》中說“如今我已經(jīng)不再專注于語言”。其實在說完這句話之后,我就已經(jīng)開始了對JavaScript的深入研究。在如此深入地研究一種語言,進而與另一種全然有別的語言比較補充之后,我對“程序=算法+結(jié)構(gòu)”有了更深刻的理解與認識——盡管這句名言從來未因我的認識而變化過,從來未因說明與命令的編程方式而變化過,也從來未因動態(tài)與靜態(tài)的實現(xiàn)方法而變化過。
動靜之間,不變的是本質(zhì)。我之所以寫這篇文字,并非想說明這種本質(zhì)是什么亦或如何得到,只是期望讀者能在匆忙的行走中,時而停下了腳步,遠遠地觀望一下目標罷了。
而我,此時刻,正在做一個駐足觀望的路人甲。?
from:?http://blog.csdn.net/aimingoo/article/details/1861213
總結(jié)

- 上一篇: “主要的编程范型”及其语言特性关系(多图
- 下一篇: 有源则至清——我读《移山之道》