如何抽象評判現有語言優劣,繼而設計一款別具優雅的計算機語言 X ?

寫個編譯器?寫個X runtime?希望認識也在思考這問題的小夥伴。


===
註:感謝朋友們的支持。但在贊同我的回答之前,我確實希望大家能看一看 @庄表偉 老莊前輩的回答,再決定大家該把自己的一票投給哪一邊。就像我在自己的專欄里說過的,「程序員好清談,尤其愛談哲學」,也往往平白生出無數的口水仗來。我自己是屬於反對談哲學這一派的,但我也承認,只要滿足工程需求第一的基本前提,談哲學未必總是壞事;而根據費希特的邏輯,不談哲學,其實也就是一種十足的哲學態度。那麼索性讓我們談哲學好了。理不辯不明,希望大家認真看完雙方的意見後,再行斟酌。
===

當你談「優雅」時,你已經不是以工程師的身份說話了。

我一貫反對那種那種追求所謂「優雅」的程序語言設計者。程序設計世界的所謂「優雅」,從來就沒有公認的,一致的定義。Haskell 狂信徒玩弄 Monad 的所謂「優雅」,和 Lisp 症候群玩弄宏構造面向對象系統的所謂「優雅」,還有 C++ 模板病患玩弄模板元編程的所謂「優雅」,從內涵到外延都沒有共同點。你拿著其中一種程序去問另外兩幫人如何評價,得到的評價十有八九是「不優雅」。提問者要追求「優雅」,沒問題,但煩請給一個規範的定義再開始討論。

寫一個編譯器,說真的,語法方面很簡單。我們手頭工具很多,老的 lex /yacc,新的 ANTLR。了解一點文法的基本原理,很容易就能做出一個自己想要的語法分析器。但評價一門語言設計的好壞,從來都不能看這個。想了解一門語言的優劣,最直接的辦法是介入那門語言的工作領域:了解 Linux 內核,才能體會 C 語言在和硬體交互時的簡潔;學過符號推演,才會理解 Lisp 為什麼將宏作為核心功能之一還會保留一個別的語言家族中看不到的 symbols 作為基本數據類型;去學 Django 和 Zope,才會理解 Python 在整合不同領域代碼時的優勢;去學科學計算,才能理解 FORTRAN 在代碼優化時的強大;理解 UNIX 系統管理時遇到的種種問題,才會理解 Perl 設計時看似混亂複雜的語法在處理實務時的方便。對上述領域都有了解,才不會犯那種試圖用一種完美標準評判所有語言的毛病;因為我們會知道,語言總是隨著應用走,而應用需求不同,本無所謂好壞。

所以評判語言,只能就某幾個具體的語言特性,在具體的實踐中,討論其實現的合理性。這才有意義。拋開具體的工作領域,卻大談語言在某種抽象層面上的優劣,看似高屋建瓴,實際不過就是空對空的扯淡。

以下內容與本答案無關。

老莊前輩說我的答案有些答非所問,這個我不否認。但在評價程序設計語言的問題上,我一直是很認真地反對將所謂「優雅」這種評判標準放進來的。我入行時間不算很長,可也見過太多的人明裡暗裡宣揚他們所謂「優雅的設計」,但究其實質,其實無非就是炫耀自己寫程序的路數符合他們的所謂「哲學思想」或「美學理論」而已。可我想提醒那些汲汲於展示思想的程序員們:這個世界上,「思想」很廉價,有價值的是「實踐錘鍊後展現生命力的思想」。自己想出一個所謂的體系,然後用一門程序設計語言體現它,這一條只要是計算機系本科畢業的,都能做出來;但只有這種思想能夠解決人們遇到的問題,才說明它有價值。

現實本身就是扭曲、複雜、不合邏輯的。工程師這份職業存在的目的,就在於從這個扭曲複雜不合邏輯的世界中做點事,讓我們的生活過得更好一點。換言之,工程師就該是器用之學的專家。我不是說程序員就活該是不會思考的機器人,但我們的思想,應該是體現在如何解決問題,而不是體現在如何評點得失上。易經雲,「形而上者謂之道,形而下者謂之器」,這話本身不帶價值判斷。而程序設計世界裡卻多的是這種人,不屑專心鑽研器用的學問,卻一廂情願地以為自己生來便是悟道的命;覺得手中握著程序設計語言,就可以用來展示自己的理想教化世人。因著這種無聊的妄念,多少人把大好時光浪費在自以為的「優雅」上,還以為別人都不如自己先知先覺。平心而論,工程的隊伍里要是失去這樣的人物,真談不上什麼損失。


「優雅」的定義非常複雜

  • 比如科學家學術派(類似我)就更喜歡特性完備、正交性好、可擴展的語言,如 Scheme
  • 而工程師會喜歡能解決他的問題的語言,比如有人喜歡 Go 就是這麼回事

水平不夠,不敢對現有語言的優劣妄自菲薄。

但我可以說說我理解的「優雅」: 針對某個問題領域,該門語言的解決方案是優雅的

拿兩個比較針對性有代表性的語言來舉例:Ruby和Rust。

Ruby是面向對象語言,它的實現就比Java優雅,簡潔一致性的對象模型,將組合優於繼承體現的淋漓盡致。繼承自Lisp的block,也完美地融入了對象模型中而不失一致性,增強了Ruby的DSL能力。這就是優雅。

Rust是系統級的內存安全語言,它的實現就是比現代C++優雅,類型安全的系統+所有權機制,加上如同「嚴格的執法者」的編譯器,讓其解決內存安全和並發安全的問題,擁有了一個簡潔一致性更高的核心模型。這就是優雅。

也有人讚歎Go語言的並發之美,也有人讚歎Erlang的並發之優雅,還有人驚嘆構建於Erlang之上的Elixir。

其實我想說的是,不可能出現這麼一款編程語言,讓大眾都覺得優雅。這不是優劣的問題,而是審美的問題。


光看題目就知道這會是一個持續不斷的,公說公有理,婆說婆有理的問題(就像大專辯論大賽出的那些題目)。

首先,我不認為這個問題是有「唯一解」的問題(下面會說到為什麼我是這麼認為的),所以我們應該摒棄爭論哪個答案(究竟「優雅」是否語言的第一位)才是宇宙真理的潛意識。

其次,才是回歸到這個問題的具體層面。在這個層面上,我同時認同@陳甫鵃 和@庄表偉的答案,本答案也不是為了提出第三種說法,而是希望從另外一個角度把上面兩位沒有說到的一些事情說清楚。

閱讀答案後我發現,其實兩個答案爭論的不是答案的錯和對,而是兩個答案在「兵器譜」上的排名:

  • 語言的設計應該從形式上應該符合數學上的美學(即滿足各種應該有的數學公式和邏輯,諸如語義的邏輯完備性、正交性等等)
  • 語言的設計應該保證從物理上解決我們遇到的實際問題

雖然我同時贊同這兩個答案,但是我本人更傾向於認同@陳甫鵃 的這種敘述結構(所以實際上我只在@陳甫鵃 的答案上點了Up小按鈕)。我更認同語言不管如何發展,其最根本的目的不是完善語言本身,而是更好的表意(可能是表人意,也可能是表物意)

因為在我的哲學中,我更認同數學應服務於物理、理論應服務於實際這種宏觀的設計理念。即應該是先有問題,再找解決方案,而不是先依賴有一個天才「創造」出一系列數學公式和理論框架,然後把現實情況往這些條條框框中塞的「削足適履」的行為。

但為什麼我仍然認為@庄表偉 說的也是對的?因為已經有無數的實踐已經證明,天才的理論不斷的指導我們走上更好的康庄大道,例如當香農提出著名的資訊理論公式後,當前的信息化才真正找到了堅實的基礎。也就是說,我認為計算機語言學的一系列理論一直都在指導我們找到最好的解決問題的方案、指引我們找到不同的解決方案根本的局限性,或者指引我們發現更加本質的問題。

說到最後,我認為這兩個回答並沒有對錯之分,只是在我看來,@陳甫鵃 的答案揭示的更為本質而已。


什麼語言都有髒話
什麼語言也都有詩歌
好的髒話可以是詩歌
有口無心的詩歌還不如髒話


如果你非要優雅,那麼首先,把你的語言要編寫的的目標程序縮小到一個小範圍裡面。


作者:Abby Chau
鏈接:如何抽象評判現有語言優劣,繼而設計一款別具優雅的計算機語言 X ? - Abby Chau 的回答
來源:知乎
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。

要對比兩款語言優不優雅,則必須要在相近的主要應用場景和可能應用場景比較。
比如說actionscript 比c 優雅是很奇怪的事。
通常愈低階的語言應用場景愈廣,愈難學習,也愈難讀。
應用場景愈窄的語言,設計起來更像是一組庫,找到重合的地方,包含更高級的操作,比如說vb6 和php。
如果有一種語言,在同一個代碼量級下,以更少的操作方式,達到同一個應用廣度,我應為就已經算更優雅了。

就我看來,c++ 的auto pointer,和php 的associative array,都是極優雅的設計。雖然背後犧牲了性能。

然後就到,到底在同一個記憶體用量級同用時級下,以更短的代碼完成,算不算優雅。但這基本上是在恆量語法設計是不是易於編譯器或者解釋器優化的問題了。

然後又更微小也常常被人拿來討論的東西:
優雅包不包括只用一種方法完成工作呢?(python vs perl)
包不包括直譯器友好度?(Lua 和js 看起來優雅很大程度也因此而已)
包不包括代碼支援原生UTF8,支援記憶體操作,支援內嵌其他語言,等等無數既定場景的常用功能等等呢?

即使對於優雅的定義也僅此而已,我們也還是無法為他們權重...
不同的場景有不同的優雅,但就我看來swift和rust 這些新世代語言都挺優秀的。


不加任何限定,泛泛的談說一種語言是否優雅肯定是不對的。
所以對於語言是否優雅的定義,應該這麼來:
對於某一類特定的使用場景和使用人群而言:
1.這個語言足夠完整。這是前提。
2.在1的基礎上,語言足夠簡潔
3.在2的基礎上,語言足夠符合目標使用場景和使用人群的思維方式。

以C和C#為例,對於習慣過程化編程的人而言,不用說C語言比C#優雅;而對於習慣了面向對象對象編程的人而言,C的優雅其實是沒有意義的,因為它不夠完整,所以C#是優雅的。

所以你不可能設計一門在所有場合都「優雅」的語言。你能做到的最佳就只能是在某一種特定的場合下達到最佳。

對於樓上的「特性簡潔」的判定標準我不是特別同意。只有當一個語言增加的某個特性不是特別必須並且會給語言的其它部分帶來不良反應的情況下,我覺得才能認為這個這個特性有損「優雅」。比較好的例子是c#里的attribute,這是個很多C#程序員一輩子都不會去真正用到的特性。然而這個特性給系統級編程帶來的好處卻絕對可以說它讓C#更優雅了一些。


優雅真是個複雜性問題。。。。,一般通用性語言眾口難調,難寫優雅,還是寫個DSL的語言比較好


真正的優雅 和 偏執 甚至瘋狂地追求極端是兩回事!


你不得不承認 有些語言的優雅就是能夠讓程序員提高生產力!
在絕大部分的眼中 我相信 優雅的定義 就是用簡單的方法或者最直接最直觀的方式或途徑 實現目的。
相比複雜度高的語言,我更喜歡簡單直接 簡稱 「優雅」 的計算機語言。
我相信 糟粕和精華 是有區別的。別跟我說 所有語言都是優雅之類的話。我覺得我們還是客觀一點站在絕大多數程序員的角度——人性的角度看待這一問題。
更優雅 的計算機語言 使用起來就是更讓人覺得 心情愉悅!

如何抽象評判現有語言優劣,繼而設計一款別具優雅的計算機語言 X ?
寫個編譯器?寫個X runtime?希望認識也在思考這問題的小夥伴

我不想說某些大牛 的發言是錯誤的,但是我一定要說,他們的發言是建立在他們的較高境界的發言,因此相對而言 有高下立判的 嫌疑,未必適用於絕大多數程序員。即使他們在使用不同的語言的時候他們其實也一定會也會遇到問題,也會有偏好。。。事實絕對不會像他們所說出的那樣。。。至少他們也和絕大部分人選擇了主流的計算機語言不是么。

目前,主流的計算機語言都各有優勢。無論是語言本身的「優雅」或者「特色」,還是運行庫帶來的強大的便利性。
很多公司和個人也一直都在開發新的計算機語言,這種行為一直都沒有停止過。
2005年到目前為止 有不少語言就都是出自大公司之手。例如oc,go,swift,rust 等...

每種語言出現的時候 心都很大。但是由於目前很多技術都存在一定的瓶頸。
直接導致 當真正是實現出來之後 並沒有人們想像中那麼優雅。
沒辦法,要成功就要取捨,要放棄,要妥協。不管是某些二進位兼容性的妥協,還是gc和native的妥協。是的,現實就是魚和熊掌往往不能兼得。你非要兼得 結果就是 要麼兩個都是雞肋,或者最終偏向另一個。

不過,即使如此,我依然股利 題主 不停止你追求美好,追求優雅的腳步。
從0開始,從有到無,經歷過,就會明白為什麼 很多東西不能像你想像中的那麼優雅。
不過或許真的也能夠為社區為學術做出一點貢獻。畢竟任何人都有潛力 有權力去 創造一個心中 「優雅」 的語言。


我不知道題主所謂的優雅指的是什麼?作為一個程序員,我關心的是:

1、可靠性如何?

可靠性更多的是依靠編碼者的水平與測試用例,而不是語言本身。當然程序的機器可讀性影響著自動化測試的實現程度。

至於類型檢測這些語法層面的東西,確實能夠減少程序員的顧慮,編寫代碼時需要考慮的東西少了,工作效率確實能高一點點。

另外自動化檢測總是比人可靠。記得剛開始拼SQL語句的時候,不管如何警惕,最近半年的代碼總是會有一兩處注入漏洞,導致在實現ORM自動處理SQL語句之前只能靠犧牲運行效率採取SQL參數模式。

2、可讀性如何?

多數人關注的是代碼的維護者,我認為主要取決於三個方面:業務邏輯的複雜度、團隊規範約束、代碼編寫者的水平。而語法層面的影響基本可以忽略,更多的是個人習慣問題,因為語法都是些簡單的東西。

我還關心目標程序對於程序是否可讀。比如運行時可讀的元數據可以產生新的抽象模式。靜態類型相比於動態類型,語義目標更明確,編譯期可讀取的元數據可以用於輔助實現自動化。

3、抽象能力如何?

抽象能力決定著程序的復用效率,不管是編寫還是維護,工作量的大小都應該是O(n)與O(1)的區別。當然某種抽象模式對於大規模應用,應該做到易讀易調試,比如C語言中的宏與動態語言中的eval就是反例。

4、可維護性如何?

我認為主要取決於三個方面:自動化程度、代碼的可讀性、模塊化的程度。

5、運行效率如何?

編譯器是必不可少的,對於需要多次運行的代碼,不管是及時編譯,還是動態編譯,又或是解釋混合編譯,都能獲得不錯的運行效率。

優先選擇靜態類型。動態類型需要大量額外的開銷,比如類型處理與字典查找,比較適合作為膠水語言而存在。另外,動態類型數據的本質就是一個字典,外加幾個類型裝換的細節處理。在C#中不使用dynamic也很容易通過包裝Dictionary&模擬動態類型數據。比如我可以在C#寫這樣的代碼:

XXX a = 1, b = "2", x = new XXX(new object());
a["x"] = 3;
a["f"] = (func&)((XXX x) =&> x + 1);
XXX c = a["f"].c(a + b), d = c["f"].c(a + a["x"]);

回應一下@庄表偉 的吐槽,我投了反對票,並認為沒有幫助,至於為什麼。。。
有人認為一行少敲幾下鍵盤叫做優雅,但是這真的重要嗎?
有人認為抽象特性少叫做優雅。我在想這些人真的願意生活在石器時代?抽象特性難道不是為了解決某類問題產生的工具?
有人認為邏輯相似的代碼敲N遍不影響思路。每次都能敲正確?維護N份代碼不會漏掉某處?比維護1份代碼想的問題少?
可能是因為我的思考模式是網狀遍歷模式,不是直線式的。可是這和強因果、邏輯有什麼衝突呢?難道寫程序可以沒有jmp、沒有call、沒有ret?面向對象就是總結事物之間的共同點與不同點,再分解到一個樹狀結構,它不是萬能的,只是N種抽象模式中的一種而已。如果真的那麼討厭面向對象,我想沒有任何人可以阻止你使用面向過程的寫法。

由於@陳甫鵃 反對元編程,所以我沒有給他贊。但是我贊同他的:語言特性,在具體的實踐中,討論其實現的合理性,這才有意義。

對於解決實際問題,少寫幾個關鍵字並不能帶來工作量上質的變化,僅僅是做法或者寫法不同而已。而由於寫法不同產生的生產力對於項目開發進度的影響幾乎是可以忽略的。純技術上的開發效率主要來源於兩方面:一是類庫的完善程度,二是自動化的支持程度。

舉個元數據應用的例子,網路通訊應該是很常見的應用吧。最初的方案是使用Socket傳輸位元組流,然後寫個程序逐個位元組解析,我相信很多人都經歷過這種折磨。這種方案問題在於,幾乎每種通訊數據類型都需要不同的編碼與解碼程序,工作量巨大。由於web的流行,一些人選擇了HTTP協議,對於複雜的數據選擇了XML或是JSON作為數據解析基礎,甚至演化出了RESTful。在統一了通訊協議並明確了數據解析協議以後,工作量產生了質的變化,當然是犧牲了一些運行效率的。雖然工作效率已經不錯了,但是有些人還是覺得調用傳參不夠方便明確,於是基於介面服務的網路調用方案WCF出現了。基於介面就註定了WCF的繁瑣,其實網路通訊的本質,就是遠程函數調用。所以我個人更傾向於基於函數原型的調用,也就是要讓網路函數調用與本地函數調用同樣簡單。

TCP 介面服務框架 - C# 高性能自動化服務端框架 - 凹凸架構 的TCP網路調用可以如此簡單明了:

定義一個服務介面

/// & /// ref / out 參數測試介面
/// &
[AutoCSer.Net.TcpInternalServer.Server(Host = "127.0.0.1", Port = 12600)]
public interface IRefOut
{
/// & /// ref / out 參數測試
/// &
/// &

加法左值& /// &

加法右值& /// &

乘積& /// &和&
AutoCSer.Net.TcpServer.ReturnValue& Add(int left, ref int right, out int product);
}

定義一個服務類實現該服務介面

/// & /// ref / out 參數測試 示例
/// &
class RefOut : IRefOut
{
/// & /// ref / out 參數測試
/// &
/// &

加法左值& /// &

加法右值& /// &

乘積& /// &和&
public AutoCSer.Net.TcpServer.ReturnValue& Add(int left, ref int right, out int product)
{
product = left * right;
int sum = left + right;
right &<&<= 1; return sum; } }

啟動服務端

AutoCSer.Net.TcpInternalServer.Emit.Server&.Create(new RefOut())

客戶端調用

int right = 3, product;
AutoCSer.Net.TcpServer.ReturnValue& sum = AutoCSer.Net.TcpInternalServer.Emit.Client&.Create().Add(2, ref right, out product);


現實的都不會太優雅,優雅是高於(脫離)現實的


跟語言無關,你可以把c++用得很優雅,也可以把c++用得很臭流氓。


藝術來源於生活。


scheme 就夠了。Common Lisp這種定義函數還多浪費一個關鍵字的除外。


推薦閱讀:

解釋器里出錯列印調用堆棧是怎麼實現的?

TAG:編程語言 | 編程 | 計算機 | 編譯原理 | 編譯器 |