不同語言各有長處,也有其主要或特定應用平臺,經常地,開發者必須依應用程式需求選擇不同的語言;就現今而言,使用多個語言來開發大型應用程式並非稀奇之事,身為開發者,最終必然得面對多種語言的學習與應用,開發者總希望能直接轉移已熟悉的概念與習慣,減少新觀念的學習,無法這麼做時,就會開始認為新學習的語言是困難的,甚至帶著與之對抗的心態來使用它。

語言有不同模型與平臺細節
有些程式語言確實會有些共通的元素或概念,它們的型態系統會有類似子集,通常具有變數概念,語言大都支援程序式(Procedural)設計,可使用函式或副程式來封裝演算流程,提供循序(Concatenation)、選擇(Selection)與重複(Repetition)的流程控制結構,支援物件導向的主流語言,則通常提供類別的定義與繼承,有些語言會特意模彷另一門語言的某些元素與概念,甚至是提供相同或類似的語法,讓開發者在使用時因為具有高度的熟悉感與連結感,而快速地接受該門語言。

在這樣的情況下,有些開發者因而有了錯誤的認知,認為語言間只稍認識一下語法關鍵字的不同,應用上就可快速而無痛地轉換。

思考一下,就可瞭解這是個迷思,如果兩門語言具有完全相同的模型、平臺與細節,它們可以解決的問題與本身產生的問題必然相同,那其中一門語言就沒有存在的必要,不同語言存在的原因,往往是在類似的型態系統子集、變數概念、流程控制結構以外的模型、平臺與細節。

循序、選擇與重複的流程控制結構,實際上是基於程序式設計的結構化設計(Structural programming)模型,命令式(Imperative)語言大多支援這種模型,然而命令式模型之外還有函數式(Functional)模型,結構化設計中常出現的迴圈語法,在函數式模型中並不存在;多數支援物件導向的語言,物件行為或繼承大都是基於類別(Class-based),然而亦有基於原型(Prototype-based)的物件導向語言,函數式語言亦並非僅使用函式,物件導向亦可與函數式結合進行設計。不同模型會有不同思考方式,撰寫程式與解決問題的方式也會因而不同。

更多時候,選擇使用一門語言,不單只是語言本身支援的模型問題,平臺與語言細節往往亦有著極大的差異性。

以整數為例,在不同語言的中,整數到底是基本型態還是物件?會不會自動型態轉換?在大數的運算支援上是顯式(Explicit)或隱式(Implicit)?整數真的就是整數嗎?

開發者往往在脫離語言間共同元素後,開始學習新觀念與細節時,因為不熟悉或與過去經驗相衝突,產生了抗拒心態,因而產生各種抗拒行為。

對抗語言心態下的行為
當懷抱著對抗心態來使用另一門語言時,最常見的行為就是將某語言的使用習慣帶到另一門語言,像是寫得像C的Java,寫得像Java的Python等,最後往往導致程式複雜而難以維護,甚至缺乏效率。

舉例而言,Java有private等權限控制,然而Python中沒有,從Java轉移至Python的開發者,經常嘗試在Python中實作複雜的資料存取控制,以實現資料隱藏的概念,隱藏資料有時有其必要,然而盲目地在不必要場合試圖隱藏資料,一點都不Python化(Pythonic),只是在用Java的使用習慣來對抗Python這門語言。

相對於抱怨另一門語言為何沒有先前使用語言的某個功能?為何先前語言不用寫某些語法,而這門語言中要寫?則是另一種抱怨。Python在類別中定義方法時,第一個參數慣例上使用self名稱來接受物件本身,表面看來,self相當於Java的this,為何Java可以省略而Python不能省略?只想少打四個字母的對抗心態下,將無法瞭解這個機制下帶來的好處。

否決另一門語言的行為或模型,也是常見的對抗行為。熟悉基於類別物件導向語言的開發者,習於定義與繼承類別來實現物件導向,在基於原型的JavaScript竄紅的這幾年來,有些開發者無法接受基於原型也是物件導向的支援方式,試圖用基於類別模型來實作類似的繼承機制,忽略或排斥原型鏈(Prototype chain)繼承的行為,對原型物件行為時不時興起的爭論,有如當年為爭論Java中傳遞物件行為是否為傳值(Pass by value)而動輒興起的戰火。

學過某種語言,在面對另一門語言時會加快學習速度嗎?對於學習語言間共同的子集來說是對的,對語言中不同模型與平臺細節則不是。習慣命令式語言的開發者,面對函數式語言時普遍認為是困難的,是因為經驗中共同的子集很少,許多新觀念是需要學習的,回想我們學習第一門程式語言,所有觀念都是全新時,不也覺得有許多困難需要克服?

拋棄舊習慣,看見語言價值

過去的經驗,確實對程式語言中共同子集的學習有速度上的幫助,不過絕非快到近乎神話的程度,像是有C++三到四年以上的經驗,就能在兩天內瞭解Java語言、程式庫、開發工具、Java EE仍至OSGi框架使用的程度嗎?

即使是透過教育訓練也不可能,這種迷思在我先前專欄〈教育訓練的迷思〉中提過,實際上這也是對抗語言心態下的產物。如果舊有經驗與習慣會令開發者產生迷思,那不如拋棄它們以發掘語言的價值。

物件導向中資料隱藏是個概念,指的是開發者應思考哪些物件狀態不應被存取,而應透過公開協定來操作,如果沒有確實思考過這個觀念,在Java中依舊有人會為了一時方便,隨意地放寬private為其他權限,即使在無原始碼可修改情況下,依舊嘗試使用反射(Reflection)來存取。當然,沒有適當機制,誤用也是會發生的,Python中使用命名混淆(Name mangling), __xyz名稱實際上會被替換為_classname__xyz,代表這是不可直接存取的資料,做為Python化的開發者,都知道不該碰觸這樣的名稱。開發者對自己的程式碼負責,是Python語言、社群的文化價值。

Python中定義方法時,第一個參數是接受物件本身的self,表面上看來,這是Python明確比隱含好(Explicit is better than implicit)的哲學,實際上,Guido van Rossum本人表示過,Python支援程序式設計,就某種程度上還有物件導向設計,在foo.meth(arg)這樣的物件外衣下,實際上會轉為C.meth(foo, arg)的呼叫,其中foo為C類別的實例參考,而這也給了動態修改類別定義一個可能性,例如有個定義為def meth(myself, arg)的函式,就可透過C.meth = meth插至類別C,成為類別的方法定義。

採用實用主義來享用語言
馬克吐溫(Mark Twain)說過:「當你的手中只有鐵錘時,你看到的東西就只有鐵釘而已。」帶著舊有習慣、價值觀來使用一門語言,雖然手中不是鐵錘,但腦袋中只想著把它當作鐵錘來用,實際上看到的東西就還是只有鐵釘。

在《Masterminds of Programming》這本書中問到Guido van Rossum,有無任何基礎觀念有助於精通Python程式開發,Guido的回答是實用主義(Pragmatism),而不要對資料隱藏、存取控制這些理論觀念過於緊張(Hung up)。如果舊有語言使用習慣與新接觸的語言特性有所抵觸時,從實用角度來理解新語言特性,想想新特性的語義實際上可解決什麼問題,享受該特性的方便,會是比對抗它來得有益處,像是JavaScript的原型特性,實際上為它保留極大的可塑性,使得創建各種程式庫來為JavaScript做各式風格補牆(Spackle)成為可能,不但可隨心所欲地模擬各種物件導向風格,甚至擷取各語言優點來創造出Node.js整個生態圈,也已然實現。

專欄作者

熱門新聞

Advertisement