怎樣解決程式語言之間的差異性問題?
毫無疑問,不同的程式語言間存在著很多差異性。那麼對於這種差異性開發者應如何解決?本文就來一探究竟。
以下為譯文:
我一直在告訴別人:“程式設計非常了不起。”在你有任何想法的時候,都可以編寫軟體,然後願望就實現了。這很真實。與建立物理的東西不同,首先你需要建立整個工廠,而軟體的擴張相對非常容易。你可以找到所有已經編譯好的元件,而且是免費的,拿來就可以用。建立好一段程式碼後,就可以重複使用無數次,而無需花錢。聽起來很厲害的樣子。
但有時候不是這樣的。程式設計帶給人的驚喜只是暫時的。在建立了很多程式碼以後,在寫程式碼的過程中你會不斷遇到讓人迷惑的錯誤。一旦你習慣了特定語言和框架的模式後,一旦你需要第二種天性去掌握所選語言中非自然的語法時,程式設計的偉大之處就不復存在了。
更別提我們有無數種不同的程式語言。每當開發人員面對特殊語言的語法而深感沮喪時,他們都會想“為什麼我們不能建立一種新的語言改正這個問題呢?”有些人還真的這麼做了,很幸運的是自然選擇已經淘汰了很多很差的語言(有時也有意外,比如至今PHP還存在)。一旦一門新的語言開始在一群開發者中流行起來,那麼恭喜你 ,現在又出現了一個新的開發者社群,他們互相合作,努力讓這門特殊的語言發展壯大。
每一種新語言的誕生所帶來的創新,都能造福我們每一個人。但是有時也有不利的一面。有些人可能寫了一些非常有用的開源JavaScript庫,但是從事Python的開發者卻完全沒法用。他們不得不自己寫一個Python版本的函式庫,或者用JavaScript重寫所有程式碼。再想想當前有多少種語言和框架。如果你不覺得這很荒謬的話,那隻能說明或許你在軟體開發這一行太長時間,已經習以為常了。
語言都包含些什麼?
各種程式語言都在以下三個方面上有著很大的不同:語法、語義和標準庫。
沒錯,我知道,我過於簡化它們了,但是聽我給你解釋。
1. 語法
如果不遵循語法,那麼你會在編輯器中看到各種彎彎曲曲的紅線,而且你的程式碼也無法通過編譯器或直譯器。
JavaScript使用大括號,布林型使用小寫的true和false,用//表示行註釋。
Python用縮排,布林型用首字母大寫的True和False表示,用#表示行註釋。
Haskell又有完全不同的語法:
2.語義
所有程式語言都有大多數相同的特徵:變數賦值、數字相加、字串操作、呼叫函式、等等。
然而,每種語言都有特殊的思想,以特定的方式執行。可以將它們劃分成不同的模式(命令式、物件導向、函式式),但是即便是兩個相同模式的程式語言在細節上也是完全不同的。
在“宣告類”,“呼叫函式”,或“定義引數的型別”時,你定義了程式的語義。有些語言遵循這樣一套規則,而其他的遵循別的規則。比如:C++中宣告的類可以延伸到多個類。當你使用“+”將數字和字串加到一起的時候,根據語言的語義會得出不同的結果。一些程式語言會因為型別不匹配而導致編譯失敗,但是有些程式語言會自動將數字轉換成十進位制的字串。
語法與語義的關係就相當於用單詞(語法)來表達想法(語義)。你可以通過語言的語法來表達語義。
3.標準庫
最後,每種語言都有各自的軟體包,我們稱之為“標準庫”。
在Python中,你可以呼叫如下函式:
標準庫是一門語言中重要的組成部分。它可以為語言帶來活力,沒有標準庫,你無法簡單地做出任何東西。
很諷刺的是,並沒有“標準的標準庫”。每個標準庫基本上都不同於其他庫:一些庫只提供最低限度的方法,而有些庫則提供非常廣泛的函式,所以開發人員基本上不需要依賴任何第三方庫。
基本的想法
以上我們介紹了一門語言的構成,接下來我有一個基本的想法:我們是否可以找到一種方法清晰地分割語法、語義和標準庫呢?我們又如何實現這一想法呢?
第一步:只有程式設計師關心語法
我想解決的第一個問題就是語法。編譯器和直譯器擁有更加有效的方式表現程式碼,我們稱之為抽象語法樹。我們用程式碼描述的內容最終可以用如下抽象語法樹表示:
如果仔細觀察,你會發現上述語法樹可能來自多個語言。是Python?是JavaScript?還是C++?這都無所謂:所有這些語言都擁有同一個語法樹。
當然,現實的例子會更加複雜。這就是為什麼我們用文字寫程式碼的原因:更加緊湊,更加易於書寫,還有更加易於閱讀(有人可能有不同的看法)。從程式設計誕生的第一天,我們採用的就是這種方法,很少有人對此質疑。
對於一個更加現實的例子來說,抽象語法樹會描述所選語言的語義(例如:類的定義)。但是擁有類似語義的語言之間還是可以共享同一個抽象語法樹,並可以擴充套件到一定範圍。這非常實用,因為你可以自動轉化部分程式碼。
所以,我們可以把語法想象成抽象語法樹之上的人類思維。程式碼可能並不會以文字的形式儲存在任何地方,僅在文字編輯器內。如果你想在特殊的語言上使用不同的語法,也完全可以。這不會影響到別人。
我其實有點驚訝怎麼沒有一種工具可以將程式碼從一種語言轉換成另一種語言,這完全可行啊。我猜肯定有人試過,但是放棄了,因為如果不將整個標準庫轉換過去的話是沒有實用性的。很明顯,我也在做這方面的嘗試。
第二步. 將標準庫抽象成API
API是一個非常高明的概念。每個軟體都可以通過API與其他軟體溝通。移動端的應用可以通過API與伺服器交流。伺服器可以通過API與資料庫交流。每個人都可以通過API與他人對話。這是一件很酷的事情。
為什麼我要在這裡討論API?因為這正是我們所需要的。API是語言的媒介。它們是一套語義,可以描述一個特殊程式碼模組對外提供的功能。無論是函式庫,HTTP伺服器,或是別的。
宣告API的方式多種多樣。可以是NPM上的JavaScript模組,並在README檔案內提供API文件。也可以是程式碼中明確宣告的API,比如TypeScript模組。也有可能並沒有API的宣告,也沒有清晰的文件。
但是重要的是:API宣告瞭程式碼模組的”對外介面“,你可以用其他語言重寫模組內部的程式碼,但API不會發生改變。這就是API的魅力所在。雖然程式語言一團糟,但是API很酷。
前面我們提到了標準庫,並說了各個語言都擁有完全不同的標準庫。如果我們能想個辦法將標準庫抽象出來,做成乾淨利落的API,那麼我們就可以解決這個問題。雖然在語義上,呼叫print("Hello")與Java呼叫System.out.println("Hello")不同,但是其實它們可以是同一個API。
我們有兩種方法可以解決這個問題。要麼我們讓大家都不要再使用標準庫了,轉而使用我們的“API層”。或者我們可以讓計算機自動推斷你使用的程式碼。我並不看好“說服大家改變他們的方式”,所以我會選擇後一種方法。
我們不用為程式語言的標準庫中的每個函式都提供API。一般我們只可能用到標準庫中的幾個函式。我們可以自動將這些程式碼從一種語言轉換到另一種語言。然後,我們只需要每個開發都用這些API替換具體的標準庫的呼叫。不用擔心,計算機依然需要你,至少現在需要。
第三步:把所有東西都做成API
現在我們有了乾淨的程式碼模組定義的純粹的語義,並將與標準庫的互動抽象成了API。
下一步做什麼?建立API。
現今的程式碼庫有多個檔案構成,彼此之間通過“import語句”互相引用。這對於我們來說很便利,但是這也意味著我們需要在腦海中勾畫程式碼庫的結構。任何一個地方發生小的變化,都可能在不經意期間給別的地方帶來破壞性的影響,尤其是如果我們沒有做好自動測試的話。而且,程式碼庫會不斷增長,而編譯的時間會逐漸加長。
也許有更好的方法解決這個問題。比如模組化就是個好辦法。
我之前寫過關於模組化的文章(點選這裡檢視:https://medium.com/@fwouts/the-zenc-master-plan-c693bf3b265e),基本上來說:每段獨立的程式碼都應該抽象成API。我稱之為模組。你無需在意一個具體的模組使用什麼語言編寫的。在寫模組的時候,你不用匯入這些檔案。實際上,這時檔案已不復存在。你可以直接使用API,它們會自動載入這些功能。
模組有什麼好處?
我不確定第三步之後會發生什麼,但是我覺得所有人都會很滿意。
以下為譯文:
我一直在告訴別人:“程式設計非常了不起。”在你有任何想法的時候,都可以編寫軟體,然後願望就實現了。這很真實。與建立物理的東西不同,首先你需要建立整個工廠,而軟體的擴張相對非常容易。你可以找到所有已經編譯好的元件,而且是免費的,拿來就可以用。建立好一段程式碼後,就可以重複使用無數次,而無需花錢。聽起來很厲害的樣子。
但有時候不是這樣的。程式設計帶給人的驚喜只是暫時的。在建立了很多程式碼以後,在寫程式碼的過程中你會不斷遇到讓人迷惑的錯誤。一旦你習慣了特定語言和框架的模式後,一旦你需要第二種天性去掌握所選語言中非自然的語法時,程式設計的偉大之處就不復存在了。
更別提我們有無數種不同的程式語言。每當開發人員面對特殊語言的語法而深感沮喪時,他們都會想“為什麼我們不能建立一種新的語言改正這個問題呢?”有些人還真的這麼做了,很幸運的是自然選擇已經淘汰了很多很差的語言(有時也有意外,比如至今PHP還存在)。一旦一門新的語言開始在一群開發者中流行起來,那麼恭喜你 ,現在又出現了一個新的開發者社群,他們互相合作,努力讓這門特殊的語言發展壯大。
每一種新語言的誕生所帶來的創新,都能造福我們每一個人。但是有時也有不利的一面。有些人可能寫了一些非常有用的開源JavaScript庫,但是從事Python的開發者卻完全沒法用。他們不得不自己寫一個Python版本的函式庫,或者用JavaScript重寫所有程式碼。再想想當前有多少種語言和框架。如果你不覺得這很荒謬的話,那隻能說明或許你在軟體開發這一行太長時間,已經習以為常了。
語言都包含些什麼?
各種程式語言都在以下三個方面上有著很大的不同:語法、語義和標準庫。
沒錯,我知道,我過於簡化它們了,但是聽我給你解釋。
1. 語法
如果不遵循語法,那麼你會在編輯器中看到各種彎彎曲曲的紅線,而且你的程式碼也無法通過編譯器或直譯器。
JavaScript使用大括號,布林型使用小寫的true和false,用//表示行註釋。
function doSomething() { a = true; if (a) { ... // Do something. } }
Python用縮排,布林型用首字母大寫的True和False表示,用#表示行註釋。
def doSomething(): a = True if a: ... # Do something.
Haskell又有完全不同的語法:
doSomething :: IO () doSomething = do let a = True if a then ... -- Do something. else return ()
2.語義
所有程式語言都有大多數相同的特徵:變數賦值、數字相加、字串操作、呼叫函式、等等。
然而,每種語言都有特殊的思想,以特定的方式執行。可以將它們劃分成不同的模式(命令式、物件導向、函式式),但是即便是兩個相同模式的程式語言在細節上也是完全不同的。
在“宣告類”,“呼叫函式”,或“定義引數的型別”時,你定義了程式的語義。有些語言遵循這樣一套規則,而其他的遵循別的規則。比如:C++中宣告的類可以延伸到多個類。當你使用“+”將數字和字串加到一起的時候,根據語言的語義會得出不同的結果。一些程式語言會因為型別不匹配而導致編譯失敗,但是有些程式語言會自動將數字轉換成十進位制的字串。
語法與語義的關係就相當於用單詞(語法)來表達想法(語義)。你可以通過語言的語法來表達語義。
3.標準庫
最後,每種語言都有各自的軟體包,我們稱之為“標準庫”。
在Python中,你可以呼叫如下函式:
- print():在控制檯輸出資訊
- len():返回陣列的長度
- 以及各種實用的模組,例如:json,threading,等等
標準庫是一門語言中重要的組成部分。它可以為語言帶來活力,沒有標準庫,你無法簡單地做出任何東西。
很諷刺的是,並沒有“標準的標準庫”。每個標準庫基本上都不同於其他庫:一些庫只提供最低限度的方法,而有些庫則提供非常廣泛的函式,所以開發人員基本上不需要依賴任何第三方庫。
基本的想法
以上我們介紹了一門語言的構成,接下來我有一個基本的想法:我們是否可以找到一種方法清晰地分割語法、語義和標準庫呢?我們又如何實現這一想法呢?
第一步:只有程式設計師關心語法
我想解決的第一個問題就是語法。編譯器和直譯器擁有更加有效的方式表現程式碼,我們稱之為抽象語法樹。我們用程式碼描述的內容最終可以用如下抽象語法樹表示:
圖:歐幾里得演算法的抽象語法樹
如果仔細觀察,你會發現上述語法樹可能來自多個語言。是Python?是JavaScript?還是C++?這都無所謂:所有這些語言都擁有同一個語法樹。
當然,現實的例子會更加複雜。這就是為什麼我們用文字寫程式碼的原因:更加緊湊,更加易於書寫,還有更加易於閱讀(有人可能有不同的看法)。從程式設計誕生的第一天,我們採用的就是這種方法,很少有人對此質疑。
對於一個更加現實的例子來說,抽象語法樹會描述所選語言的語義(例如:類的定義)。但是擁有類似語義的語言之間還是可以共享同一個抽象語法樹,並可以擴充套件到一定範圍。這非常實用,因為你可以自動轉化部分程式碼。
所以,我們可以把語法想象成抽象語法樹之上的人類思維。程式碼可能並不會以文字的形式儲存在任何地方,僅在文字編輯器內。如果你想在特殊的語言上使用不同的語法,也完全可以。這不會影響到別人。
我其實有點驚訝怎麼沒有一種工具可以將程式碼從一種語言轉換成另一種語言,這完全可行啊。我猜肯定有人試過,但是放棄了,因為如果不將整個標準庫轉換過去的話是沒有實用性的。很明顯,我也在做這方面的嘗試。
第二步. 將標準庫抽象成API
API是一個非常高明的概念。每個軟體都可以通過API與其他軟體溝通。移動端的應用可以通過API與伺服器交流。伺服器可以通過API與資料庫交流。每個人都可以通過API與他人對話。這是一件很酷的事情。
為什麼我要在這裡討論API?因為這正是我們所需要的。API是語言的媒介。它們是一套語義,可以描述一個特殊程式碼模組對外提供的功能。無論是函式庫,HTTP伺服器,或是別的。
宣告API的方式多種多樣。可以是NPM上的JavaScript模組,並在README檔案內提供API文件。也可以是程式碼中明確宣告的API,比如TypeScript模組。也有可能並沒有API的宣告,也沒有清晰的文件。
但是重要的是:API宣告瞭程式碼模組的”對外介面“,你可以用其他語言重寫模組內部的程式碼,但API不會發生改變。這就是API的魅力所在。雖然程式語言一團糟,但是API很酷。
前面我們提到了標準庫,並說了各個語言都擁有完全不同的標準庫。如果我們能想個辦法將標準庫抽象出來,做成乾淨利落的API,那麼我們就可以解決這個問題。雖然在語義上,呼叫print("Hello")與Java呼叫System.out.println("Hello")不同,但是其實它們可以是同一個API。
我們有兩種方法可以解決這個問題。要麼我們讓大家都不要再使用標準庫了,轉而使用我們的“API層”。或者我們可以讓計算機自動推斷你使用的程式碼。我並不看好“說服大家改變他們的方式”,所以我會選擇後一種方法。
我們不用為程式語言的標準庫中的每個函式都提供API。一般我們只可能用到標準庫中的幾個函式。我們可以自動將這些程式碼從一種語言轉換到另一種語言。然後,我們只需要每個開發都用這些API替換具體的標準庫的呼叫。不用擔心,計算機依然需要你,至少現在需要。
第三步:把所有東西都做成API
現在我們有了乾淨的程式碼模組定義的純粹的語義,並將與標準庫的互動抽象成了API。
下一步做什麼?建立API。
現今的程式碼庫有多個檔案構成,彼此之間通過“import語句”互相引用。這對於我們來說很便利,但是這也意味著我們需要在腦海中勾畫程式碼庫的結構。任何一個地方發生小的變化,都可能在不經意期間給別的地方帶來破壞性的影響,尤其是如果我們沒有做好自動測試的話。而且,程式碼庫會不斷增長,而編譯的時間會逐漸加長。
也許有更好的方法解決這個問題。比如模組化就是個好辦法。
我之前寫過關於模組化的文章(點選這裡檢視:https://medium.com/@fwouts/the-zenc-master-plan-c693bf3b265e),基本上來說:每段獨立的程式碼都應該抽象成API。我稱之為模組。你無需在意一個具體的模組使用什麼語言編寫的。在寫模組的時候,你不用匯入這些檔案。實際上,這時檔案已不復存在。你可以直接使用API,它們會自動載入這些功能。
模組有什麼好處?
- 可以鼓勵大家考慮設計:首先你需要設計API
- 可以降低認知的開銷:你僅需要“填空”
- 簡化測試:你只需測試API,並可以模擬所有的依賴性
- 世界會變得更加美好:沒有了語言之間的壁壘,沒有了巨大的程式碼庫;程式設計師更加快樂,客戶更加快樂
我不確定第三步之後會發生什麼,但是我覺得所有人都會很滿意。
來自: CSDN資訊
相關文章
- 解決MongoDB儲存時間時差的問題MongoDB
- 關於shell上面語法和windows編輯器差異造成問題解決Windows
- 設計差異引發WebServices安全性問題Web
- 資料庫中的欄位id間斷問題大家使怎樣解決的?資料庫
- 怎樣成為解決問題的高手?——關於問題解決的關鍵4步驟
- 怎麼解決內容的原創性問題
- C語言之詭異字串C語言字串
- JVM 異常退出的問題解決JVM
- 程式、會話、連線之間的差異會話
- [AlwaysOn] AlwaysOn可用性組的可用性模式之間的差異模式
- angular-resource版本差異問題Angular
- 利用sys schema解決一次詭異的語句hang問題
- 全球化思考:怎樣克服交流中的文化差異
- 怎樣解決更新MacOS big sur時遇到的那些問題!Mac
- 深入sql多表差異化聯合查詢的問題詳解SQL
- shell 計算時間差的問題
- 解決FRA空間滿的問題
- oracle程式異常中止時登入掛起問題的解決Oracle
- 編譯語言、解釋語言與指令碼語言之間的區別編譯指令碼
- 解決double型別相減有誤差的問題型別
- IBM版本差異的高明解決辦法IBM
- 怎麼樣解決macOS遭遇惡意軟體入侵問題Mac
- 解決ie相容性問題
- 像程式設計師一樣思考——提高解決問題的能力程式設計師
- 系統之間差異
- swap空間不足問題解決
- 深度解密Go語言之關於 interface 的10個問題解密Go
- OAF helloworld 學習異常問題解決
- 怎麼解決程式設計師上網問題程式設計師
- 夜遊專案怎樣以文化差異吸引遊客
- 智慧經營系統怎麼樣?解決了什麼問題?
- 在防護DDoS時會遇到哪些問題,該怎樣解決?
- 如何解決unity做遊戲面臨的重複程式碼過多 程式碼複用性差的問題Unity遊戲
- 異地獨生子女結婚怎麼解決父母養老問題?
- C語言解決排序問題C語言排序
- 利用C語言小程式來解決大問題(轉)C語言
- python和GO語言之間的區別!PythonGo
- 全域性替換 ‘/home’ 為 ‘/’ 的問題解決!