冒號課堂
第五課 語言小談(3)
5.3動態(tài)語言——披著彩衣飛舞的腳本語言
故凡天下之理,欲向動上求靜,靜上求動 ——《蔡牧堂·發(fā)微論》
關(guān)鍵詞: 動態(tài)語言,靜態(tài)語言,腳本語言
摘要: 動態(tài)語言簡談
!預(yù)覽
· 程序是為終端用戶服務(wù)的,而腳本是為程序員服務(wù)的
· 動態(tài)語言秉承的一個理念是:優(yōu)化人的時間而不是機器的時間
· 待靜態(tài)語言披盔戴甲、備馬抬槍之際,動態(tài)語言已衣袂飄飄,長劍出手了
· 當腳本語言披上動態(tài)語言的彩衣,昔日不起眼的毛毛蟲便羽化成碟,開始飄舞在眾人追逐的目光之中
?提問
· 腳本與程序的區(qū)別是什么?
· 腳本語言有什么特點?為什么適合作粘合語言?
· 動態(tài)語言有什么特點?它與腳本語言究竟有什么分別?
· 動態(tài)語言也能用于大型應(yīng)用開發(fā)嗎?
· 動態(tài)語言會最終取代靜態(tài)語言嗎?
:講解
嘆號急不可耐地問:“現(xiàn)在可以談動態(tài)語言了吧?”
冒號感言:“曾幾何時,動態(tài)語言還只是陪太子讀書的角色,那時候它們的名字是‘腳本語言’。近來卻迅速崛起,儼然有與靜態(tài)語言分庭抗禮之勢。”
問號忍不住問道:“動態(tài)語言與腳本語言是一回事嗎?”
“相比動態(tài)語言定義上的模糊,腳本語言的概念還是比較明確的。”冒號回避直接給出答案,“腳本(script)的提法,是為了區(qū)別于一般的程序(program)。Perl的發(fā)明者Larry Wall不愧為語言學(xué)家,對此有一個精彩的說法:‘A script is what you give the actors, a program is what you give the audience’。直譯為:腳本是給演員看的,節(jié)目是給觀眾看的。此言妙在一語雙關(guān)——program兼有‘節(jié)目’和‘程序’的意思。”
句號領(lǐng)會其意:“這里的演員指的是程序員,觀眾指的是用戶。換言之,程序是為終端用戶服務(wù)的,而腳本是為程序員服務(wù)的。”
“正解!”冒號肯定道,“腳本最常見的形式是殼腳本(shell script),在非Unix類的操作系統(tǒng)中也稱為批處理文件(batch file)。”
“批處理文件倒是很熟悉,殼腳本聽起來就怪怪的。”逗號嘀咕著。
“那是因為你在Windows的世界里長大,聽不慣Unix的方言。”冒號一語道破緣由,“操作系統(tǒng)的內(nèi)核稱為核(kernel),出于安全考慮不便直接與用戶交互,因此裹上一層殼(shell),即人們常說的命令行解釋器(command line interpreter)。殼腳本是在殼上運行的腳本,擴展了命令行下可執(zhí)行的命令。它最初主要是內(nèi)建(built-in)命令的組合,用于系統(tǒng)程序的調(diào)度,是系統(tǒng)管理員的必備武器。其后,殼腳本也發(fā)展到用于應(yīng)用程序的調(diào)度、連接、調(diào)試等,成為粘合(glue)語言。”
逗號不禁有些疑問:“難道一般的程序語言如C之類的不能作此用嗎?”
引號回應(yīng)道:“這些語言通常需要‘編寫-編譯-鏈接-運行’的循環(huán)過程,十分繁瑣。腳本語言編寫后即可運行,快捷方便得多。”
冒號點點頭:“不錯,既然腳本主要用于整合其他程序,本身并不占用太多的資源,同時邏輯也不太復(fù)雜,因此腳本語言注重簡潔、實用,語法要求不那么嚴格,性能上的要求也不高。除殼腳本外,還有一些專用于文本處理(text processing)的語言或工具如AWK、sed和grep等,多用于讀寫配置文件和日志文件、過濾處理各種程序的輸入和輸出,對于整合各種程序也非常實用。隨著對腳本語言需求的增長,其局限性日益突出,以Perl為代表的高級腳本語言便應(yīng)運而生了。Perl在殼腳本、AWK、sed的基礎(chǔ)上,融合了命令式的C與函數(shù)式的Lisp的特征,漸漸成為最流行的腳本語言之一。”
問號注意到:“JavaScript是瀏覽器端的腳本,來路似乎有些不同。”
冒號解釋道:“除了命令行程序外,腳本語言在其他的應(yīng)用程序中也身影頻現(xiàn),如圖形界面應(yīng)用、多媒體應(yīng)用、網(wǎng)絡(luò)應(yīng)用等。尤其是網(wǎng)絡(luò)應(yīng)用,成為滋生和繁榮腳本語言最肥沃的土壤。例如:Perl非常廣泛地用于網(wǎng)絡(luò)服務(wù)器端的CGI編程;PHP更是專為動態(tài)網(wǎng)頁而設(shè)計的語言;Ruby雖與Java同歲,但真正開始風(fēng)行得益于網(wǎng)絡(luò)應(yīng)用框架Ruby on Rails的成功;至于JavaScript,長期被邊緣化為網(wǎng)頁設(shè)計人員的語言,是web2.0的新寵AJAX真正將其帶入程序員的視線。”
逗號有些好奇:“什么時候腳本語言變成了動態(tài)語言呢?”
“盡管動態(tài)語言并無確切的定義,但不是所有的腳本語言都能稱作動態(tài)語言的——比如Bash之類的殼腳本語言(shell script language);另一方面,也不是所有的動態(tài)語言天生就是為腳本服務(wù)的——比如Lisp[1]。不妨這么理解,腳本語言以語言的實際用途為標志,動態(tài)語言以語言的語法特征為標志。”冒號回答,“單從用途上看,一個腳本語言如果不再局限于命令行工具和粘合工具,從專用語言發(fā)展為通用語言,并能勝任復(fù)雜的應(yīng)用開發(fā),或許更有資格歸為動態(tài)語言。”
句號發(fā)現(xiàn):“動態(tài)語言似乎對字符處理都特別擅長。”
冒號道:“腳本語言與一般程序一個不同之處是,它一般是面向字符而非數(shù)值的,因為字符是最通用的接口,正好發(fā)揮其粘合作用,而數(shù)值運算對性能要求較高,多由核心程序來完成。動態(tài)語言繼承了這個特點,并且除了正則表達式(regular expression)外,為字符串、數(shù)組、列表、集合、映射等常用結(jié)構(gòu)提供了豐富簡潔的運算,遠比靜態(tài)語言依賴于庫(library)的方便自然得多。”
嘆號問:“我們清楚了腳本語言中‘腳本’的來歷,那動態(tài)語言中‘動態(tài)’又體現(xiàn)在何處呢?”
“問得好!”冒號聞言,正中下懷,“再從用法上看,動態(tài)語言能在運行中增加或改變數(shù)據(jù)結(jié)構(gòu)、函數(shù)定義、對象行為或指令流程等。如果說動態(tài)類型語言的動態(tài)體現(xiàn)在類型上,動態(tài)語言的動態(tài)則體現(xiàn)在結(jié)構(gòu)和功能上。相比而言,靜態(tài)語言雖然也可能實現(xiàn)同樣的效果,但既不方便也不自然[2]。另外不容忽視的一點是,動態(tài)語言大多是開源的,其本身的發(fā)展也更具動態(tài)性。”
引號非常注重理論:“動態(tài)語言的語法特征有那些?”
“動態(tài)語言秉承的一個理念是:優(yōu)化人的時間而不是機器的時間。為提高人的生產(chǎn)率,寧肯犧牲部分的程序性能或者購買更高配置的硬件。由于硬件相對于人件一直在貶值,該理念便有了合理的現(xiàn)實基礎(chǔ)。”冒號講述著,“從語法上看,動態(tài)語言為了更好地粘合來自不同系統(tǒng)、不同語言的程序,對類型的要求一般不如靜態(tài)語言那么嚴格,代碼更加簡潔自由,故而多為動態(tài)類型的和弱類型的,天然支持泛型式編程。當然這不是絕對的,比如Groovy也支持靜態(tài)類型,Scala完全是靜態(tài)類型的,Python一般認為是強類型的。大多數(shù)動態(tài)語言支持eval函數(shù),能動態(tài)執(zhí)行任意字符串形式的代碼,并有豐富的反射(reflection)機制,天然支持元編程。動態(tài)語言很多還支持包括高階函數(shù)(high-order function)和閉包(closure)等在內(nèi)的函數(shù)式編程。此外,大多動態(tài)語言也支持對象式編程,如Python、Ruby、Perl 5、PHP 3等。”
句號補充道:“許多動態(tài)語言還支持過程式編程和并發(fā)式編程,簡直把主要的編程范式一網(wǎng)打盡了!”
“其實Python、Ruby和Groovy等還可以進行切面式編程,這對于支持元編程的動態(tài)語言來說非常自然,因為切面式編程一般都是通過元編程來實現(xiàn)的。”冒號進一步指出,“而邏輯式編程語言的代表Prolog,同樣有動態(tài)語言的特征。至于事件驅(qū)動式編程嘛,對支持callback的語言來說都不是難事。”
引號高興地看到:“九大編程范式無一漏網(wǎng)啊!”
嘆號較為感性:“靜態(tài)語言給人的感覺是沉穩(wěn)持重,而動態(tài)語言則活潑輕快。如果同時用靜態(tài)語言和動態(tài)語言編程,豈不培養(yǎng)出雙重人格?”
“程序員本就是雙重人格的。”冒號淡淡地說,“你總結(jié)得沒錯,兩類語言的風(fēng)格的確大相異趣:待靜態(tài)語言披盔戴甲、備馬抬槍之際,動態(tài)語言已衣袂飄飄,長劍出手了。不過,如果是應(yīng)付強敵的長期大規(guī)模作戰(zhàn),靜態(tài)語言還是有優(yōu)勢的。”
引號聽聲辨音:“這意味著動態(tài)語言不適用大型應(yīng)用開發(fā)嗎?“
“這么說未免有些武斷。”冒號并不同意,“誠然,動態(tài)語言的語法比較寬松,相對容易出錯。但也有人辯稱,動態(tài)語言的代碼量少于相應(yīng)的靜態(tài)語言,bug應(yīng)該更少。有人認為動態(tài)語言調(diào)試不如靜態(tài)語言方便,有人卻說隨著IDE的日益強大,出錯幾率和找錯成本也在減少。談到運行效率,動態(tài)語言雖然多為解釋型語言(interpreted language),但許多也提供了與Java類似的字節(jié)碼編譯(bytecode compilation)甚至JIT編譯(just-in-time compilation)。動態(tài)語言在某方面甚至還更勝一籌:譬如一個類的接口如果發(fā)生變動,在靜態(tài)語言中所有該類的子類和一些相關(guān)類都可能需要重新編譯、連接,這在大型應(yīng)用中是非常耗時的,而動態(tài)語言則大可不必,這當然不足為奇——在它眼里類結(jié)構(gòu)本來就是能動態(tài)改變的。除此之外,越是大型的程序,越耗費人力和時間成本,客戶需求的變化也越大,因而對程序的靈活性、適應(yīng)性和開發(fā)周期提出了更高的要求。動態(tài)語言在這些方面比靜態(tài)語言更有優(yōu)勢,并且還能作為快速原型(rapid prototyping)開發(fā)的工具。”
“快速原型開發(fā)?”問號一臉的疑惑。
冒號簡作介紹:“這是一種軟件開發(fā)的方式。舉例來說,為了快速搭建一個系統(tǒng),以適應(yīng)不斷變化的客戶需要,可以先采用開發(fā)效率更高的動態(tài)語言。在交付時再將其轉(zhuǎn)化為編譯型的靜態(tài)語言。如果系統(tǒng)對性能的要求不高,這種轉(zhuǎn)化至多是局部的。有的干脆一字不易,不僅省了當下的時間,以后維護起來也更方便。”
逗號耍起了貧嘴:“這就叫:替補變成了主力,配角變成了主角,媳婦熬成了婆婆。”
嘆號開始擔(dān)憂起來:“聽您這意思,動態(tài)語言優(yōu)點突出而弱點并不突出,這樣下去靜態(tài)語言還有市場嗎?”
冒號坦然道:“動態(tài)語言小快靈的風(fēng)格的確吸引了越來越多人的注意,也漸漸走入靜態(tài)語言的世界。Java平臺和.Net平臺不僅為Ruby和Python等動態(tài)語言鋪設(shè)了跑道,而且為培植諸如Groovy等動態(tài)語言提供了土壤。同時,Java和C#本身也融進了越來越多的動態(tài)特征。”
句號斷言:“靜態(tài)語言這種融合性結(jié)合內(nèi)在的安全性、穩(wěn)定性,以及較高的性能、成熟度和接受度,都決定了它不可能被動態(tài)語言完全取代。”
“對!”冒號堅定地表示贊同,“當腳本語言披上動態(tài)語言的彩衣,昔日不起眼的毛毛蟲便羽化成碟,開始飄舞在眾人追逐的目光之中。但靜態(tài)語言也絕不會淡出人們的視線,它如矯健的蒼鷹,依然有搏擊長空的雄力。程序員只要保持嚴謹?shù)淖黠L(fēng)和開放的心態(tài),既有穩(wěn)如泰山的馬步,又有一躍凌空的飛腿,靜如處子,動如脫兔,如履平地般游走于高高的梅花樁上,絕無跌落之虞。”
一股豪情在眾人心中蕩漾開來。
冒號看了看時間,斂起眼中精光,同時收起話匣:“關(guān)于動態(tài)語言,今天還是先簡單談到這里吧。”
,插語
[1] Lisp本身以及一些變種如Emacs Lisp、AutoLISP等也能作為腳本語言,但那畢竟不是Lisp語言的初衷。
[2] 一些設(shè)計模式(如裝飾模式、訪問者模式等)就是為了賦予靜態(tài)語言一定的動態(tài)特征。
。總結(jié)
- 程序是為終端用戶服務(wù)的,腳本是為程序員服務(wù)的。
- 腳本語言一般是解釋型語言,不需要通過“編寫-編譯-鏈接-運行”的循環(huán)圈,便利快捷,加之簡潔寬松的語法、面向字符的特性以及較強的文本處理能力,尤其適合作為粘合語言,多用于系統(tǒng)管理和集成。
- 腳本語言與動態(tài)語言盡管并不完全重合,但更多地還是提法上的區(qū)別。前者強調(diào)作為命令行工具和粘合工具的語言用途,后者強調(diào)動態(tài)的語言特征。當腳本語言不再局限于粘合語言,從專用語言發(fā)展為通用語言,并且勝任復(fù)雜的應(yīng)用開發(fā)的時候,動態(tài)語言的提法顯然更加合理。
- 動態(tài)語言能在程序運行期間改變數(shù)據(jù)結(jié)構(gòu)、函數(shù)定義、對象行為或指令流程等,相比靜態(tài)語言在結(jié)構(gòu)和功能上的更具動態(tài)性。
- 動態(tài)語言重在優(yōu)化人工時間而非機器時間,因此相比靜態(tài)語言,其開發(fā)效率較高,但運行效率較低。
- 動態(tài)語言的以下特點決定了它在大型應(yīng)用開發(fā)中的價值:代碼量較少,從一定程度減輕了維護難度;不少提供了字節(jié)碼編譯或JIT編譯,彌補了運行效率上的不足;一些模塊的結(jié)構(gòu)和功能上的變化不會導(dǎo)致相關(guān)模塊的重新編譯和連接;具有靈活、適應(yīng)力強和開發(fā)周期短的特點,能快速響應(yīng)客戶需求的變化,并且適合快速原型開發(fā)。
- 靜態(tài)語言安全穩(wěn)定、性能優(yōu)越、成熟普及,并且逐漸開始吸納動態(tài)語言的一些優(yōu)點,這些都決定了它不可能被后者完全替代。
“”參考
[1] Wikipedia.Dynamic programming language.http://en.wikipedia.org/wiki/Dynamic_language
[2] David Ascher.Dynamic Languages—ready for the next challenges, by design.http://www.activestate.com/corporate/publications/ActiveState_Dynamic_Languages.pdf