7年編程語言設計精華總結——寫給想創造或正在創造一門新編程語言的同學


無論因為什么,你可能想要自己造一個語言。在具體實施之前,請聽我一些忠告。

首先開發語言是一個一非常漫長又辛苦的過程,現在很多成功的語言都是由一個大公司的團隊經過幾年的打造才完成的,如果你不能保證長期的投入,建議還是放棄這個念頭,以免前功盡棄。

其次,你得明確你的語言的亮點是什么。除非你的亮點足以使用戶可以這個接受學習新語言的成本,否則它很難會被用戶接受。但這很困難。你可能覺得你現在用的語言能用,但總有那么幾個不爽的地方,所以你決定造一門自己的語言,至少在某些地方比其他語言要好用,要牛逼。然而光幾個細微的改進是遠遠不夠的,就像誰都知道核桃難剝,但還是會買來吃一樣,不是說你做了一個已經剝好殼的核桃仁,就會比那些沒剝殼的核桃好賣。

編程語言的用戶是程序員,而絕大多數的程序員都是負責“搬磚”的,他們選擇一個編程語言,不是因為這門語言有多好用,只是單純地因為這門語言能讓他找到工作,所以如果你創造一個沒有人用的新語言,即使這門語言你真的做的很好,也不會有人對它感興趣,更何況新語言實際並沒有你所說的那么好。

怎么算開發編程語言

如果你以為做一個新語言的 parser 就算完成一個新語言了,那你太弱了。

一個完整的語言,需要有編譯器,需要有 IDE 支持,需要有完整的標准庫,還需要有適用的場景以及配套的工具。單純的 parser 只占了整體工作的 5% 不到。

你可能會說,我就做個 parser,然后翻譯成別的語言,這確實能節省不少的工作,但 IDE 支持呢,還有調試怎么辦?如果這些不解決好,你會發現,用新語言的開發成本還不如用以前的。

大括號還是縮進式

總有那么幾個人很討厭 Shift 鍵,輸入一對大括號加回車縮進要按鍵6次,而采用縮進式語法,可以少敲4次,特別是在終端里面打代碼的時候,縮進式語法要爽不爽,所以那些不怎么打代碼的,一些電腦愛好者,或者是運維、黑客,更偏向於縮進式語法。

但縮進式語法也有幾個缺點讓專業程序員討厭,首先是縮進式的語法在視覺上,層次沒有大括號清晰,如果編輯器沒有縮進線,代碼又很長,那更恐怖了。其次,要從別的地方抄一段代碼,大括號可以一鍵格式化還不出錯,而縮進式的就要頭疼了,對於經常抄代碼的碼農來說,這是最不能忍的。最后,如果告訴你,你的 BUG 是因為代碼中的幾個空格導致的,你可能會抓狂。

強類型還是弱類型

無論怎樣的語言都會有變量,變量的類型是否可變,決定了整個語言的基調。從實踐角度,手動標注類型,有利於項目的長期發展,但短期成本較高,而無需標注類型的腳本語言,短期成本低,但項目變大后,維護成本會突然上升。所以現在新語言的趨勢,是強弱類型混合,再輔以類型推導,這樣短期弱類型為主,等到項目變大后,逐步調整為強類型。

關鍵字要多還是少

有一批人認為,語言應該做的盡量簡潔,關鍵字要盡量少,最好是沒有,一切都是函數,包括 if。

也有一批人認為,關鍵詞越多,說明語言的功能越多,只有功能強大語言才好用。

此外還有一批吃瓜群眾說:你就做的和現在語言做的一模一樣就可以了,語法多了看不懂,語法少了不夠用。

其實每個人的立場不同,就像你和大爺說人艱不拆他可能聽不懂,但如果你正式地說“請不要拆穿我們”,好像也怪怪的。有一些語法,能懂的人覺得是便利,不能懂的人覺得是天書。選擇用一個既有的語法組合,以盲目創造新的語法,要優秀很多。

代碼不是越短越好(不然你讀讀文字超短的文言文看看?),代碼寫的越短,意味着讀者要猜的越多。優秀的語言往往是用一句短但不產生歧義的代碼,完成盡可能多的事情。

有 while 還需不需要 do..while

do..while 和 while 類似,只不過多執行一次循環,很多搬磚的按親身體驗說:“do..while 是個啥,從沒用過。”

所有的 do..while,都可以寫成 while,但且沒有增加多少代碼量,也沒有降低可讀性。

比如 

do {
   執行操作()
} while(!操作是否成功())

可以寫成:

while(true) {
   執行操作()
   if (操作是否成功()) {
       break
   }
}

而且實際業務中的場景,多數是這樣的:

while(true) {
   執行操作()
   if (操作是否成功()) {
       break
   }
   執行初始化()
}

所以 do..while 的場景更少了。

如果不考慮和現有語言的兼容性和用戶習慣,去掉沒什么影響。

switch 要不要允許自動穿越 case

很多代碼檢測工具都會檢測 switch 是否丟失了 break,從實踐角度,忘寫 break 是一個經常犯的錯,所以從源頭堵截錯誤,看樣子是有用的。

很多新語言也確實這么做了。但還是有一些場景,需要穿越 case,比如兩個 case 共用一個邏輯。

引入逗號隔開的表達式可能是一個方案:

switch (x) {
    case 1, 2, 3:
       // ...
    case 4, 5, 6:
       // ...
}

這個方案缺點是兩個 case 的邏輯要不全共用,要不全不共用,更好一點的做法是像 GO 語言一樣引入關鍵字:

switch (x) {
    case 1: 
        fallthrough
    case 2:
       // ...
}

或者改變 continue 的含義,使得 switch 中的 continue 用來繼續下個 case:

switch (x) {
    case 1: 
        continue
    case 2:
       // ...
}

要不要有 null

有很多人說 null 是個糟糕的設計,我們應該拒絕 null,但那依然存在於很多語言之中,最主要的原因是性能。

現在語言的趨勢是,提供 null,但也配備了完整的 null 檢測工具,比如 ??, ?. 運算符

= 只能是語句還是允許表達式

如果 = 作為語句,可能會把判斷中的 == 誤寫成 =。

有的人還會說,= 作為獨立的一行語句,可以更清晰地知道,變量的值在什么時候被修改了,除非刪除閉包函數內覆蓋外部變量的功能,否則變量的值仍然可能在一個沒有 = 的表達式中被修改。

將變量的定義和使用盡量放在一起,有助於提高代碼的可讀性,甚至還有人建議在 if 里直接聲明變量:

if (var x = foo()){
   x.abc // x 不是 null
}

這都說明了,允許將 = 放在表達式任意位置,可以簡化代碼,提高可讀性。

Python 不允許等號出現在表達式,因為表達式中的 = 表示了函數參數名。

 要不要支持Unicode字符作為變量名,全部還是部分?

支持變量名中文?廢話,不多說!但,支持所有非ASCII字符作為變量名怎么樣?不行,因為:

1. 代碼會不容易查錯,因為個別字符是不可見的。

2. 可能存在安全問題,比如將不良代碼偽裝成不可見字符。

3. 並不是所有的編輯器、終端完整支持所有 Unicode。

 

=====待補充======

?好你在干什么 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM