那些讓碼農倍感痛苦的現代編程語言
特定編程語言的優缺點是什么?X是我的任務很好的語言嗎?搜尋"最佳編程語言"將為您提供" Python,Java,JavaScript,C#,C ++,PHP"的標準列表,以及優缺點的模糊列表。看到這樣的文章會讓我感到痛苦,他們的作者一定是完全懶惰,缺乏經驗,同時又缺乏想象力。讓我們深入研究一下,找出真正的缺點,而不是什么。
在本文中,我將嘗試對流行的(而不是那么流行的)現代編程語言進行客觀,公正的概述,從最壞到最好的排名。
請記住,沒有一種編程語言可以完美地適合所有可能的用例。一些語言最適合于前端開發,其他語言最適合于后端/ API開發,其他語言則非常適合系統編程。
我將介紹世界上兩個最常見的語言家族-語言是C衍生的,而語言是ML衍生的。
編程語言只是開發人員工具箱中的工具。選擇正確的工具來完成這項工作很重要。我真的希望本指南將幫助您選擇最適合您任務的編程語言。做出正確的選擇可以節省您數月(甚至數年)的開發工作。
哪些語言特征真正重要?
大多數其他類似的文章都根據受歡迎程度和潛在收入等因素進行比較。受歡迎程度很少是一個很好的衡量標準,尤其是在軟件領域(盡管大型社區和生態系統會有所幫助)。相反,我將考慮特定語言的優點和缺點。
我將使用大拇指(即+1),大拇指朝下或OK(無論好壞)表情符號來表示特定語言特征的得分。
現在,我們將如何衡量?換句話說,除了語言流行之外,真正重要的是什么?
一、類型系統
許多人按類型系統發誓。因此,近年來諸如TypeScript之類的語言開始流行。我傾向于同意,類型系統消除了程序中的大量錯誤,并使重構更加容易。但是,"擁有"類型系統只是故事的一部分。
如果語言具有類型系統,那么進行類型推斷也非常有用。最好的類型系統能夠推斷大多數類型,而無需顯式注釋功能簽名。不幸的是,大多數編程語言僅提供基本的類型推斷。
對于類型系統來說,支持數字數據類型也很好(稍后會詳細介紹)。
最強大的類型系統支持高級類型,這是泛型之上的抽象級別,并允許我們以更高的抽象級別進行編程。
我們還必須記住,人們往往對類型系統過于重視。有些事情遠比靜態類型重要,選擇類型時,類型系統的存在與否并不是唯一的因素。
(1) 學習曲線
我們可能擁有完美的編程語言,但是如果新入職的開發人員可能要花費數月甚至數年(前期投資)來學習,它將有什么用?另一方面,某些編程范例需要花費數年才能變得精通。
一門好的語言應該適合初學者,并且不需要花幾年的時間就能掌握。
(2) 空值
我稱之為我的十億美元錯誤。它是1965年創建的空引用。當時,我正在設計第一個全面的類型系統,用于面向對象的語言中的引用。我的目標是確保對引用的所有使用都絕對安全,并由編譯器自動執行檢查。但是我忍不住要插入一個空引用的誘惑,僅僅是因為它很容易實現。這導致了無數錯誤,漏洞和系統崩潰,在最近四十年中可能造成十億美元的痛苦和破壞。
-空引用的發明者托尼·霍爾(Tony Hoare) |
為什么空引用不好?空引用中斷類型系統。當null為默認值時,我們將不再依賴編譯器來檢查代碼的有效性。任何可為空的值都是等待爆炸的炸彈。如果我們嘗試使用我們不認為可能為空但實際上為空的值怎么辦?我們得到一個運行時異常。
我們必須依靠手動運行時檢查來確保所處理的值不為null。即使使用靜態類型的語言,空引用也剝奪了類型系統的許多好處。
實際上,這種運行時檢查(有時稱為空防護)是針對不良語言設計的解決方法。他們用樣板亂碼。最糟糕的是,我們無法保證不會忘記檢查null。
用一種好的語言,應該在編譯時檢查值的缺失或存在。
鼓勵使用其他機制處理缺失數據的語言將排名更高。
(3) 錯誤處理
捕獲異常是處理錯誤的一種壞方法。拋出異常是可以的,但僅在例外情況下,程序無法恢復并且必須崩潰。就像空值一樣,異常會破壞類型系統。
當使用異常作為錯誤處理的主要方式時,就無法知道函數是返回期望值還是崩潰。引發異常的函數也是不可能組成的。
顯然,僅僅由于我們無法獲取某些數據而導致整個應用程序崩潰是不可能的。但這確實比我們想要的更經常發生。
一種選擇是手動檢查引發的異常,但是這種方法很脆弱(我們可能會忘記檢查異常),并且會增加很多噪音:
如今,有更好的錯誤處理機制,可能的錯誤應在編譯時進行類型檢查。默認情況下不使用例外的語言將排名更高。
(4) 并發
我們已經到了摩爾定律的盡頭,處理器將不會更快。我們生活在多核CPU時代,實際上,任何現代應用程序都必須利用多核。
不幸的是,當今使用的大多數編程語言都是在單核計算時代設計的,根本不具備可在多核上有效運行的功能。
幫助并發的庫是事后的想法,它們只是向最初不是為并發設計的語言添加了創可貼。這并不是真正的良好開發經驗。在現代語言中,必須內置并發支持(請考慮使用Go / Erlang / Elixir)。
(5) 不變性
我認為,當構建可變對象的大對象圖時,大型面向對象的程序會越來越復雜。你知道,嘗試理解并牢記當調用方法時會發生什么副作用。
— Clojure的創建者Rich Hickey。 |
如今,使用不變的值進行編程變得越來越流行。甚至像React這樣的現代UI庫也打算與不可變值一起使用。具有對不可變數據值的一流支持的語言將排名更高。僅僅因為不變性消除了我們代碼中的一整類錯誤。
什么是不可變狀態?簡而言之,它是不變的數據。就像大多數編程語言中的字符串一樣。例如,大寫字符串永遠不會更改原始字符串-始終會返回一個新字符串。
不變性進一步推動了這一想法,并確保一切都沒有改變。總會返回一個新數組,而不是更改原始數組。更新用戶名?將返回一個新的用戶對象,并更新其名稱,同時保留原始對象。
處于不可變狀態時,不會共享任何內容,因此我們不再需要擔心線程安全性的復雜性。不變性使我們的代碼易于并行化。
不改變任何狀態的函數稱為純函數,它們很容易測試和推理。使用純函數時,我們不必擔心函數之外的任何事情。只需專注于正在使用的這一函數,而忽略其他所有函數。你可能可以想象,開發變得多么容易(與OOP相比,必須牢記整個對象圖)。
(6) 生態系統/工具
語言可能不是很好,但是它可能具有龐大的生態系統,因此很有吸引力。訪問優質的庫可以節省一個月(甚至幾年)的開發工作。
我們已經看到JavaScript和Python等語言會發生這種情況。
(7) 速度
語言的編譯速度如何?程序啟動速度有多快?運行時性能如何?所有這些都很重要,并將列入排名。
(8) 年齡
盡管有一些例外,但通常來說,較新的語言會比較舊的語言更好。僅僅因為更新的語言可以從其前輩的錯誤中學習。
二、C ++

讓我們從最壞的情況入手,這可能是計算機科學中最大的錯誤之一,C ++。是的,C ++不被認為是一種嶄新的現代編程語言。但是今天它仍在廣泛使用,必須將其包括在列表中。
語言家族:C.
(1) 語言功能

C ++是一種可怕的語言……而且將項目限制為C意味著人們不會用任何愚蠢的"對象模型" c&@ p弄亂事情。— Linux的創建者Linus Torvalds。
C ++具有許多功能。它嘗試做所有事情,同時又不擅長任何特定的事情。C ++具有goto,指針,引用,OOP,運算符重載和許多其他非生產性功能。
為什么C ++如此糟糕?我認為,最大的原因是它的年齡。C ++是在1979年設計的很早的時候。當時的設計師缺乏經驗,也不知道該關注什么。當時添加的功能似乎是個好主意。該語言非常流行,這意味著添加了許多功能來支持各種用例(創建更大的功能混亂)。
(2) 速度
C ++因其編譯時間慢而臭名昭著。比Java慢得多,不如Scala。
但是,運行時性能以及啟動時間都很好。
(3) 生態/工具

以上推文很有意義。C ++編譯器
(4) 垃圾收集
我曾希望可以選擇啟用的垃圾收集器將成為C ++ 0x的一部分,但是存在足夠的技術問題……
-C ++的創建者Bjarne Stroustrup |
垃圾回收從未添加到C ++中。手動內存管理極易出錯。開發人員必須擔心手動釋放和分配內存。我將永遠不會錯過使用非垃圾收集語言的日子,如今在垃圾收集語言中很容易避免許多錯誤。
(5) attempt失敗的面向對象編程嘗試
我發明了術語"面向對象",可以告訴您我沒有C ++。
-Alan Kay,面向對象編程的發明者。 |
OOP出現于60年代后期,是C ++工作開始時的一項很酷的新技術。不幸的是,C ++在實現OOP時犯了一些關鍵錯誤(與Smalltalk等語言不同),這使一個好主意變成了一場噩夢。
與Java相比,C ++的一件好事是C ++中的OOP至少是可選的。
(6) 學習曲線
> Mercurial_Rhombus on Reddit
C ++是一種復雜的低級語言,沒有自動內存管理。由于其功能膨脹,初學者不得不花很多時間學習該語言。
(7) 并發
C ++是在單核計算時代設計的,在過去的十年中僅添加了基本的并發機制。
(8) 錯誤處理
捕獲/拋出錯誤是首選的錯誤處理機制。
(9) 不變性
沒有對不可變數據結構的內置支持。
(10) 空值
在C ++中,所有引用都是可為空的。
(11) 結論0.5星
最初旨在成為C的更好版本的C ++確實未能實現目標。
C ++的最佳用途可能是系統編程。但是,鑒于存在更好,更現代的替代方案(Rust and Go),C ++甚至不應該用于此。我認為C ++毫無優勢,請隨時證明我是錯的。
C ++,你該走了。
三、Java
自從MS-DOS以來,Java是計算機行業中最令人困擾的事情。
-Alan Kay,面向對象編程的發明者。 |
自1995年首次出現以來,Java比C ++年齡小16歲。Java是一種簡單得多的語言,這可能有助于其流行。
語言家族:C.
(1) 垃圾收集
Java提供的優于C ++的最大好處之一是垃圾收集,垃圾收集本身消除了許多錯誤。
(2) 生態
Java已經存在了很長時間,并且它具有一個龐大的用于后端開發的生態系統,從而大大減少了開發工作。
(3) 面向對象語言
在這里,我不會深入探討OOP的缺點,有關更詳細的分析,可以閱讀我的其他文章《面向對象編程—萬億美元災難》。
相反,我只是引用一些計算機科學領域最杰出的人,以得到他們對OOP的看法:
很抱歉,我很久以前就為該主題創造了"對象"一詞,因為它使許多人專注于較小的想法。大想法是消息傳遞。 -OOP的發明者艾倫·凱(Alan Kay) |
艾倫·凱(Alan Kay)是對的,主流的OOP語言專注于錯誤的事物(類和對象),而忽略了消息傳遞。值得慶幸的是,現代語言正確地實現了這個想法(Erlang / Elixir)。
使用受OOP影響的編程語言,計算機軟件變得更冗長,可讀性更差,描述性更強,更難修改和維護。
—理查德·曼斯菲爾德(Richard Mansfield) |
使用過OOP語言(例如Java或C#)并具有使用非OOP語言的經驗的任何人都可以聯系。
(4) 速度
顯然,Java在Java虛擬機之上運行,而Java虛擬機的啟動時間很慢。我已經看到,在JVM上運行的程序需要30秒甚至更長的時間才能啟動,這對于現代的云原生程序來說是不可接受的。
在較大的項目上,編譯速度很慢,這極大地影響了開發人員的生產力(盡管沒有Scala那樣糟糕)。
從好的方面來說,JVM的運行時性能確實不錯。
(5) 學習曲線
盡管Java是一種相當簡單的語言,但它對面向對象編程的關注使真正變得很難。可以輕松編寫一個簡單的程序。但是,知道如何編寫可靠且可維護的面向對象代碼可能要花十年的時間。
(6) 并發
Java是在單核計算時代設計的,并且像C ++一樣,僅具有基本的并發支持。
(7) 空值
在Java中,所有引用都是可為空的。
(8) 錯誤處理
捕獲/拋出錯誤是首選的錯誤處理機制。
(9) 不變性
沒有對不可變數據結構的內置支持。
(10) 結論 1星
Java出現時是一種不錯的語言。太糟糕了,Java(與Scala不同)一直只專注于OOP。該語言非常冗長,并且受樣板代碼的影響很大。
Java退休的時候到了。
四、C#
從根本上講,C#和Java之間幾乎沒有什么區別(因為C#的早期版本實際上是Java的Microsoft實現)。
C#與Java共享大多數缺點。C#于2000年首次出現,但比Java年齡小5歲,并且已經從Java的錯誤中學到了一些東西。
語言家族:C.
(1) 語法
C#語法一直領先于Java。C#比樣板代碼遭受的痛苦更少。盡管C#是一種OOP語言,但它在冗長的方面更為重要。很高興看到C#語法在每個版本中都得到了改進,并增加了諸如表達式強健的函數成員,模式匹配,元組等功能。
(2) 面向對象語言
就像Java一樣,C#主要關注OOP。再一次,我不會在這里花太多時間試圖說服OOP的缺點,我只想引用一些計算機科學領域的杰出人物。
我認為缺乏可重用性的是面向對象的語言,而不是函數語言。因為面向對象語言的問題在于它們擁有了它們所伴隨的所有隱式環境。你想要香蕉,但是得到的是一只大猩猩,拿著香蕉和整個叢林。
— Erlang的創建者Joe Armstrong |
我必須同意Joe Armstrong的觀點,與函數(甚至命令性)代碼相比,重用面向對象的代碼非常困難。
提供面向對象的程序作為正確程序的替代方案…… —計算機科學的先驅Edsger W. Dijkstra |
在我整個職業生涯中都使用過OOP和非OOP語言之后,我不得不同意與非OOP代碼相比,OOP代碼更難正確。
(3) 多范式?
C#聲稱是一種多范式語言。特別是,C#聲稱支持函數編程。我必須不同意,僅僅支持一流的函數還不足以使一種語言稱為函數式。
語言應具有哪些功能?至少,對不可變數據結構,模式匹配,函數組合的管道運算符,代數數據類型的內置支持。
(4) 并發
C#是在單核計算時代創建的,就像Java一樣,它僅具有基本的并發支持。
(5) 空值
在C#中,所有引用都是可為空的。
(6) 錯誤處理
捕獲/拋出錯誤是首選的錯誤處理機制。
(7) 不變性
沒有對不可變數據結構的內置支持。
(8) 結論 1.5星
我在C#的職業生涯中花費了大量時間,并且總是對這種語言感到沮喪。與Java一樣,我建議您尋找更現代的替代方案。它是相同的Java,但語法更現代。
不幸的是,關于C#并沒有什么"尖銳"的東西。
Python
自1991年首次出現以來,Python是一門古老的語言。與JavaScript一起,Python是世界上最受歡迎的語言之一。
語言家族:C.
(1) 生態
Python幾乎有任何庫。與JavaScript不同,Python無法用于前端Web開發,但是Python可以輕松地構建大量的數據科學庫。
(2) 學習努力
Python是一種非常簡單的語言,初學者可以在幾周內掌握它們。
(3) 類型系統
Python是動態類型的,關于類型系統沒有太多要說的了。
(4) 速度
Python是一種解釋型語言,以運行時性能而言,它因為是最慢的編程語言之一而臭名昭著。在運行時性能至關重要的情況下,使用Cython代替普通的Python可能是一個很好的解決方案。
與本地語言相比,Python的啟動速度也很慢。
(5) 工具
在將Python和其他現代語言一起使用后,很難不對Python的依賴項管理感到失望。pip,pipenv,virtualenv等。相比之下,JavaScript中的NPM是您唯一需要的工具。
(6) 并發
創建Python時并沒有考慮到并發性,它僅具有基本的并發支持。
(7) 空值
在Python中,所有引用都是可為空的。
(8) 錯誤處理
捕獲/拋出錯誤是首選的錯誤處理機制。
不變性
沒有對不可變數據結構的內置支持。
(9) 結論 2星
真的很不幸,Python沒有對函數式編程的適當支持。函數式編程非常適合于數據科學試圖解決的問題。即使對于諸如網絡抓取之類的非常Python的任務,函數式語言(例如Elixir)也更合適。
我不建議將Python用于大型項目,因為該語言在構建時并未考慮到嚴格的軟件工程。
當沒有其他替代方法可用時,Python不應用于數據科學以外的其他任何用途。在數據科學領域,Julia似乎是Python的一個很好的現代替代品,盡管它的生態系統還不如Python成熟。
Rust
Rust是一種現代的低級語言,最初被設計為C ++的替代語言。
語言家族:C.
(1) 速度
Rust從一開始就被設計為快速。Rust程序的編譯比Go程序的編譯花費更長的時間。Rust程序的運行時性能比Go快一點。
(2) 空值
我們列表中的第一種語言,帶有現代的null選擇!Rust沒有null或nil值,Rust開發人員改用Option Pattern。
(3) 錯誤處理
Rust采用了現代的功能性方法來處理錯誤,并使用專用的Result類型來表示可能失敗的操作。它與上面的選項非常相似,但是None情況現在也有一個值。
(4) 內存管理
Rust是我們列表中唯一沒有垃圾回收的現代語言。這迫使開發人員考慮進行低級內存管理,并使開發人員的工作效率下降。
(5) 并發
由于缺乏垃圾收集,因此在Rust中并發非常困難。開發人員必須擔心諸如裝箱和固定之類的事情,這些事情通常會以垃圾回收語言自動完成。
(6) 不變性
Rust沒有對不可變數據結構的內置支持。
(7) 低級語言
作為一種低級語言,Rust中的開發人員生產力無法達到其他高級語言中的水平。這也使學習努力變得更加困難。
(8) 結論 2星
Rust非常適合系統編程。盡管它比Go更復雜,但它提供了強大的類型系統。Rust為空值提供了一種現代的替代方法,并提供了一種處理錯誤的現代方法。
為什么Rust仍然排名低于TypeScript和JavaScript?它是為系統編程設計的低級語言。Rust并非非常適合后端/ Web API開發。它缺少垃圾收集,并且不內置對不變性的支持。
TypeScript
TypeScript是一種js編譯語言。它的主要目標是通過向JavaScript添加靜態類型來制作"更好的JavaScript"。就像JavaScript一樣,TypeScript被用于前端和后端開發。
TypeScript是由設計C#的同一人Anders Hejlsberg設計的。TypeScript代碼感覺非常CSharp,從根本上講,可以將其視為瀏覽器的C#。
語言家族:C.
(1) JavaScript的超集
是的,JavaScript的超集對TypeScript的采用起到了很大的幫助。畢竟,很多人已經知道JavaScript。
但是,作為JavaScript的超集更為不利。這意味著TypeScript承載了所有JavaScript包。它受到JavaScript中所有錯誤的設計決策的限制。
例如,有多少人喜歡this關鍵字?可能沒人,但是TypeScript故意決定保留它。
類型系統有時真的很奇怪嗎?
- [] == ![]; // -> true
- NaN === NaN; // -> false
換句話說,TypeScript具有JavaScript的所有缺點。成為一門糟糕的語言的超集并不能證明它是好的。
(2) 生態
TypeScript可以訪問整個JavaScript生態系統,這是巨大的。巨大的好處。與特別是與其他語言(例如Python)相比,Node Package Manager非常令人愉快。
缺點是并非所有JavaScript庫都具有可用的TypeScript聲明。Rambda,一成不變。
(3) 類型系統
我對TypeScript中的類型系統不太滿意。
從好的方面來說,它甚至支持數值數據類型(區分聯合)
TypeScript語法不如功能語言更好。事后考慮,在TypeScript 2.0中添加了有區別的聯合。在此開關中,我們將匹配容易出錯的字符串,如果我們錯過了情況,編譯器將不會發出警告。
TypeScript僅提供基本的類型推斷。另外,在使用TypeScript時,你會發現使用頻率比你想要的更多。
(4) 空值
TypeScript 2.0添加了對非空類型的支持,可以選擇使用–strictNullChecks編譯器標志啟用它。但。使用非空類型進行編程不是默認設置,并且在TypeScript中不視為慣用語言。
(5) 錯誤處理
在TypeScript中,錯誤是通過引發/捕獲異常來處理的。
(6) JS新功能
JavaScript比TypeScript更快地支持酷炫的新功能。使用Babel,甚至可以在JavaScript中啟用實驗性功能,而TypeScript則無法實現。
(7) 不變性
在TypeScript中處理不可變數據結構比在JavaScript中要差得多。盡管JavaScript開發人員可以使用有助于實現不變性的庫,但TypeScript開發人員通常必須依賴于本機數組/對象散布運算符(寫時復制):
不幸的是,本地傳播運算符不會執行深層復制,而手動傳播深層對象很麻煩。復制大型數組/對象也不利于性能。
TypeScript中的readonly關鍵字很好,它使屬性不可變。但是,要支持正確的不可變數據結構還有很長的路要走。
JavaScript具有用于處理不可變數據的良好庫(例如Rambda / Immutable.js)。但是,使此類庫與TypeScript類型系統一起使用可能非常棘手。
(8) TypeScript和React — 地獄般的匹配嗎?
用JavaScript [和TypeScript]處理不可變數據要比用Clojure這樣的語言處理困難。
-直接來自React文檔 |
延續先前的缺點,如果你正在進行前端Web開發,那么你很可能正在使用React。
未為TypeScript創建React。最初,React是針對功能性語言編寫的(稍后會詳細介紹)。編程范例之間存在沖突-TypeScript是OOP優先,而React是功能優先。
React希望其props(即函數參數)是不可變的,而TypeScript沒有對不可變數據結構的適當內置支持。
TypeScript通過JavaScript提供給React開發的唯一真正好處是,不必擔心PropTypes。
(9) 是TypeScript還是Hypescript?
TypeScript只是一種炒作嗎?由你決定。我認為是這樣。它的最大好處是可以訪問整個JavaScript生態系統。
為什么HypeScript如此受歡迎?Java和C#受歡迎的原因相同-得到數十億公司的龐大營銷預算的支持。
(10) 結論 2星
盡管通常認為TypeScript是"更好的JavaScript",但我認為它比JavaScript低。它提供的超過JavaScript的好處被高估了,特別是對于使用React進行前端Web開發。
TypeScript確實無法通過保留JavaScript的所有不良部分來交付,實際上無法繼承JavaScript中數十年的不良設計決策。
Go
Go旨在幫助提高多核處理器和大型代碼庫時代的編程效率。Go的設計師主要是因為他們彼此不喜歡C ++,當時在Google廣泛使用了C ++。
語言家族:C.
(1) 并發
并發是Go的"殺手級"功能,Go是從頭開始為并發而構建的。就像Erlang / Elixir一樣,Go遵循并發的消息模型。不幸的是,Go中的goroutine無法提供與Erlang / Elixir進程相同的容錯功能。換句話說,goroutine中的異常將導致整個程序崩潰,而Elixir進程中的異常將導致該程序崩潰。
(2) 速度
Google創建Go的主要原因之一是編譯速度。甚至有個笑話," Google在等待C ++代碼編譯的同時就創建了Go"。
Go是一種非常快速的語言。Go程序的啟動時間非常快。Go可以編譯為本機代碼,因此其運行速度也非常出色。
(3) 學習努力
Go是一種簡單的語言,有一定的編程經驗的人大概一個月就能學到一門。
(4) 錯誤處理
Go不支持例外,而是Go使開發人員明確處理可能的錯誤。與Rust類似,Go返回兩個值-調用結果和潛在錯誤。如果一切順利,那么錯誤將為零。
(5) 沒有面向對象的編程
盡管有些人可能會不同意,但我個人認為缺少OOP功能是一個很大的優勢。
重復Linus Torvalds:
C ++是一種可怕的[面向對象]語言…而且將你的項目限制為C意味著人們不會用任何愚蠢的“對象模型”。 — Linux的創建者Linus Torvalds |
Linus Torvalds以對C ++和OOP的公開批評而聞名。他100%正確的一件事是限制程序員他們可以做出的選擇。實際上,程序員選擇的次數越少,代碼的彈性就越大。
在我看來,Go故意省略了許多OOP功能,以免重復C ++的錯誤。
(6) 生態
一些標準庫確實很笨。它的很大一部分與Go本身返回帶外錯誤的哲學是不一致的(例如,它們為索引而不是(int,error)返回像-1的值),而其他則依賴于全局狀態,例如flag和網絡/ http。
Go的標準庫中缺乏標準化。例如,某些庫在發生錯誤返回(int,error)的情況下,其他庫則返回諸如-1的值,而其他庫則依賴于全局狀態(如flag)。
生態系統遠沒有JavaScript大。
(7) 類型系統

幾乎每種現代編程語言都有一種或另一種形式的泛型(包括可怕的C#/ Java,甚至C ++都有模板)。泛型允許開發人員針對不同類型重用函數實現。如果沒有泛型,則必須分別為整數,雙精度數和浮點數分別實現add函數,從而導致大量代碼重復。換句話說,Go中缺少泛型會導致大量重復代碼。有人說," Go"是" Go寫一些樣板"的縮寫
(8) 空值
不幸的是,數十年來,更安全的替代方法已經出現,Go語言包含了空值。
(9) 不變性
Go沒有對不可變數據結構的內置支持。
(10) 結論 2.5星
Go不是一種好語言。不算太差;只是不好。我們必須謹慎使用不好的語言,因為如果我們不謹慎,在接下來的20年中,我們可能最終會陷入困境。
-雅格(Will Yager)的《為什么Go不好》 |
如果你不是Google,并且沒有類似Google的用例,那么Go可能不是一個好選擇。Go是最適合系統編程的一種簡單語言。對于API開發,Go不是一個好的選擇(原因是因為有很多更好的選擇可用,稍后再介紹)。
我認為總體而言,Go是一個比Rust更好的選擇(盡管類型系統較弱)。它是一種簡單的語言,非常快,易于學習并且具有出色的并發功能。是的,Go成功實現了成為"更好的C ++"的設計目標。
(11) 最佳系統語言獎
最佳系統語言獎歸Go。毫無疑問,Go是系統編程的理想選擇。Go是一種低級語言,它非常適合該領域,這已被大量使用Go構建的成功項目所證實,例如Kubernetes,Docker和Terraform。
JavaScript
作為世界上最受歡迎的編程語言,JavaScript不需要介紹。
是的,這不是一個錯誤。JavaScript確實排在Rust,TypeScript和Go之上。讓我們找出原因。
語言家族:C.
(1) 生態
JavaScript的最大好處是其生態系統。JavaScript正在用于您可以想到的所有內容-前端/后端Web開發,CLI編程,數據科學甚至機器學習。JavaScript可能具有一個庫,可滿足您的所有需求。
(2) 學習曲線
JavaScript(以及Python)是最容易學習的編程語言之一。一個人可以在幾周內用JavaScript變得富有成效。
(3) 類型系統
就像Python一樣,JavaScript是動態類型的,這里沒有太多要說的了。JavaScript的類型系統有時可能很奇怪:
(4) 不變性
如TypeScript部分所述,散布運算符可能會降低性能,甚至在復制對象時也不會執行深層復制。JavaScript缺少對不可變數據結構的內置支持,盡管有一些庫可以提供幫助(Ramda / Immutable.js)。
(5) React不是為JavaScript設計的
在JavaScript中使用React時,必須使用PropTypes。但是,這也意味著必須維護PropType,這可能成為噩夢。
此外,如果您不小心,可能會引入細微的性能問題
這種看上去無辜的代碼可能成為性能的噩夢,因為在JavaScript中 []!= []。上面的代碼將使HugeList在每次更新時都重新呈現,即使options值沒有更改。在最終無法使用UI之前,這些問題可能會更加復雜。
(6) This關鍵詞
JavaScript的最大反特性可能是this關鍵字。其行為始終不一致。它是挑剔的,在不同的上下文中可能意味著完全不同的事物。它的行為甚至取決于誰調用了給定的函數。通常使用此關鍵字會導致難以調試的細微而奇怪的錯誤。
(7) 并發
JavaScript使用事件循環支持單線程并發。這消除了對線程同步機制(如鎖定)的需要。盡管JavaScript并不是在考慮并發性的情況下構建的,但是與大多數其他語言相比,使用并發代碼要容易得多。
(8) JS新功能
JavaScript比TypeScript更快地支持酷炫的新功能。使用Babel,甚至可以在JavaScript中啟用實驗功能。
(9) 錯誤處理
捕獲/拋出錯誤是首選的錯誤處理機制。
(10) 結論 2.5 星
JavaScript不是一種精心設計的語言。JavaScript的初始版本在10天內就放在一起了(盡管將來的版本已經解決了許多缺點)。
盡管有缺點,JavaScript是全棧Web開發的不錯選擇。通過適當的紀律和評價,JavaScript可以成為一門好語言。
函數式編程==放心
> Photo by Ante Hamersmit on Unsplash
讓我們先繞道而行,然后再繼續排名。為什么要煩惱函數式編程?函數式編程使我們高枕無憂。
是的,函數式編程可能聽起來很嚇人,但實際上沒有什么可擔心的。簡而言之,函數式語言做出了許多正確的設計決策,而其他語言則做出了錯誤的決策。在大多數情況下,函數式語言將具有正確的功能:具有代數數據類型支持的功能強大的類型系統,無null,錯誤處理無異常,內置的不變數據結構,模式匹配,函數組合運算符。
函數式編程語言有哪些共同的優勢使其在我們的排名中如此高?
(1) 使用純函數編程
與命令式(主流語言)不同,函數式編程語言鼓勵使用純函數式編程。
什么是純函數?這個想法非常簡單-給定相同的輸入,純函數將始終返回相同的輸出。例如,2 + 2將始終返回4,這意味著加法運算符+是純函數。
純函數不允許與外界進行交互(進行API調用,甚至無法寫入控制臺)。甚至不允許更改狀態。這與OOP所采取的方法完全相反,在OOP中,任何方法都可以自由地改變其他對象的狀態。
可以很容易地從不純函數中分辨出純函數-函數是不帶參數,還是不返回值?然后,這是一個不純函數。
這種方法似乎很局限,可能需要一段時間才能習慣。起初,這肯定讓我感到困惑!
純函數有什么好處?它們非常易于測試(無需模擬和存根)。關于純函數的推理很容易-與OOP不同,無需牢記整個應用程序狀態。您只需要擔心當前正在使用的功能。
純函數可以輕松組成。純函數對于并發非常有用,因為函數之間沒有共享狀態。重構純函數是純粹的樂趣-只需復制和粘貼,無需復雜的IDE工具。
簡而言之,純函數將歡樂帶回到編程中。
函數式編程鼓勵使用純函數-當90%以上的代碼庫由純函數組成時,這很好。一些語言將其極端化,并完全禁止使用非純函數(這并不總是一個好主意)。
(2) 不變的數據結構
下面的所有功能語言都內置了對不可變數據結構的支持。數據結構也是持久的。這只是意味著,無論何時進行更改,我們都不必創建整個結構的深層副本。一次又一次地成像復制超過100,000個項目的陣列,這一定很慢,對吧?
持久數據結構無需創建副本,而是簡單地重用對舊數據結構的引用,同時添加所需的更改。
(3) 數值數據類型
ADT是一種建模應用程序狀態的強大方法。可以將它們視為類固醇的枚舉。我們指定類型可以組成的可能的"子類型",以及其構造函數參數:
上面的"形狀"類型可以是正方形,矩形或圓形。Square構造函數采用單個int參數(寬度),Rectangle采用兩個int參數(寬度和高度),而Circle采用單個int參數(其半徑)。
我不了解你,但我肯定會使用舊版本,并以功能語言使用ADT。
(4) 模式匹配
所有功能語言都對模式匹配提供了極大的支持。通常,模式匹配允許人們編寫非常有表現力的代碼。
這是一個關于選項(布爾)類型的模式匹配的示例:
相同的代碼,沒有模式匹配:
毫無疑問,模式匹配版本更加富有表現力和簡潔。
模式匹配還提供了編譯時的詳盡性保證,這意味著我們將不會忘記檢查可能的情況。沒有以非功能性語言提供的此類保證。
(5) 空值
函數式編程語言通常避免使用空引用。而是使用Option模式(類似于Rust):
(6) 錯誤處理
通常不建議在功能語言中使用異常。而是使用Result模式(再次,類似于Rust):
要全面了解錯誤處理的功能方式,請確保閱讀OCaml中的Composable Error Handling。
(7) 管道前移運算符
如果沒有管道前移運算符,函數調用往往會變得很嵌套,這使它們的可讀性降低:
函數式語言具有特殊的管道運算符,使該任務更加容易:
(8) Huskell
語言家族:ML。
(9) 類型系統
沒有比Haskell更強大的文字系統了。顯然,Haskell支持代數數據類型,但它也支持類型類。它的類型檢查器幾乎可以推斷任何東西。
(10) 學習曲線
好家伙!為了有效地使用Haskell,必須首先精通類型理論(這不是我在開玩笑),這不是秘密。OOP需要多年的經驗來編寫體面的代碼,而Haskell則需要投入大量時間進行前期學習,才能提高生產力。
在Haskell中編寫甚至一個簡單的" hello world"程序也需要了解Monads(尤其是IO Monads)。
(11) 社區
根據我的經驗,Haskell社區的學術性更高。最近在Haskell庫郵件列表中的帖子開始于:
"在一次私人交流中向我指出,元組函數 x->(x,x)實際上是對雙應用和一些相關結構的對角化的特殊情況。"
它收到了39位漂亮的愛好者答復。 -Hacker News上的momentoftop |
上面的引用很好地總結了Haskell社區。Haskell社區對學術討論(和類別理論)更感興趣,而不是解決實際問題。
(12) 函數純度
正如我們已經了解的那樣,純函數是驚人的。副作用(例如,與外界互動,包括變異狀態)是程序中大量錯誤的原因。作為純函數式語言,Haskell完全禁止使用它們。這意味著函數永遠不能更改任何值,甚至不允許與外界進行交互(從技術上來說,甚至不允許進行日志記錄之類的操作)。
當然,Haskell提供了與外界交互的解決方法。您可能會問它如何運作?我們提供了一組說明(IO Monad)。這樣的指令可能會說:讀取鍵盤輸入,然后在某些功能中使用該輸入,然后將結果打印到控制臺。然后,語言運行庫將獲取此類指令,并為我們執行這些指令。我們永遠不會執行直接與外界交互的代碼。
不惜一切代價避免成功!
-Haskell的非正式座右銘。 |
實際上,對函數純度的這種關注顯著增加了抽象的數量,從而增加了復雜性,并因此降低了開發人員的生產率。
(13) 空值
就像Rust一樣,Haskell也沒有null引用。它使用選項模式來表示可能不存在的值。
(14) 錯誤處理
盡管某些函數可能會引發錯誤,但慣用的Haskell代碼使用的模式類似于Rust中的Result類型。
(15) 不變性
Haskell對不可變數據結構提供一流的支持。
(16) 模式匹配
Haskell具有出色的模式匹配支持。
(17) 生態
標準庫是一團糟,尤其是默認的前奏(核心庫)。默認情況下,Haskell使用引發異常的函數而不是返回選項值(函數編程的黃金標準)。更糟的是,Haskell有兩個包管理器-Cabal和Stack。
(18) 結論 3星
核心函數式編程永遠不會成為主流-它需要深刻理解許多高度抽象的概念。
-David Bryant Copeland獲得了四個更好的軟件設計規則 |
我真的很想喜歡Haskell。不幸的是,Haskell可能會永遠局限于學術界。Haskell是函數式編程語言中最糟糕的嗎?我認為是你來決定的。
OCaml
OCaml是一種函數式編程語言。OCaml代表對象Caml,但是具有諷刺意味的是,很少會在OCaml中找到使用對象的人。
OCaml幾乎和Java一樣古老,名稱中的"對象"部分可能反映了那個時代的"對象"炒作。OCaml只是在Caml離開的地方接機。
語言家族:ML。
(1) 類型系統
OCaml的類型系統幾乎與Haskell一樣好。最大的缺點是缺少類型類,但它支持仿函數(高階模塊)。
OCaml是靜態類型的,其類型推斷幾乎與Haskell一樣好。
(2) 生態
OCaml社區很小,這意味著您不會找到常見用例的高質量庫。例如,OCaml缺少一個不錯的Web框架。
與其他語言相比,OCaml庫的文檔非常糟糕。
(3) 工具
工具是一團糟。共有三個包管理員-Opam,Dune和Esy。
OCaml以非常糟糕的編譯器錯誤消息而聞名。雖然不是交易破壞者,但這有點令人沮喪,并且會影響開發人員的生產率。
(4) 學習資源
學習OCaml的首選書籍是Real World OCaml。自2013年以來,該書尚未更新,并且許多示例已過時。使用現代工具不可能遵循本書。
通常,語言教程非常差(與其他語言相比)。它們大多是學術課程的講義。
(5) 并發
" Multicore即將到來的任何一天™️" —在OCaml中并發地總結了故事。OCaml開發人員一直在等待適當的多核支持,并且似乎不會在不久的將來添加到該語言中。OCaml似乎是唯一缺少適當的多核支持的功能語言。
(6) 空值
OCaml沒有空引用,并使用選項模式來表示可能不存在的值。
(7) 錯誤處理
慣用的OCaml代碼使用Result類型模式。
(8) 不變性
OCaml對不可變數據結構提供一流的支持。
(9) 模式匹配
OCaml具有出色的模式匹配支持。
(10) 結論 3星
OCaml是一種很好的函數式語言。它的主要缺點是并發支持差,社區很小(因此生態系統很小,缺乏學習資源)。
鑒于其缺點,我不建議在生產中使用OCaml。
· 離開OCaml
Scala
Scala是為數不多的真正多范例語言之一,對面向對象和函數式編程都提供了很好的支持。
語言家族:C.
(1) 生態
Scala在Java虛擬機之上運行,這意味著它可以訪問龐大的Java庫生態系統。在后端工作時,這確實是提高開發人員工作效率的福音。
(2) 類型系統
Scala可能是唯一具有不健全的類型系統的類型化函數式語言,并且缺乏適當的類型推斷。Scala中的類型系統不如其他函數式語言那么好。
從好的方面來說,Scala支持更高種類的類型和類型類。
盡管存在缺點,但類型系統仍然非常好,因此表示贊許。
(3) 簡潔/可讀
盡管Scala代碼非常簡潔,尤其是與Java相比,但代碼可讀性不強。
Scala是實際上屬于C語言編程語言家族的幾種函數式語言之一。C系列語言旨在與命令式編程一起使用,而ML系列語言旨在與功能性編程一起使用。因此,在Scala中使用類似C語法的函數式編程有時會感到很奇怪。
Scala中的代數數據類型沒有正確的語法,這會對可讀性產生不利影響
就可讀性而言,ML語言的ADT無疑是贏家。
(4) 速度
就編譯速度而言,Scala可能是最差的編程語言之一。一個簡單的" hello world"程序可能需要10秒鐘才能在較舊的硬件上進行編譯。Scala編譯器不是并發的(使用單個內核編譯代碼),這不利于編譯速度。
Scala在Java虛擬機之上運行,這意味著程序將花費更長的時間啟動。
(5) 學習曲線
Scala具有很多功能,這使得學習變得更加困難。就像C ++一樣,該語言具有許多功能。
Scala是最困難的函數式語言之一(僅次于Haskell)。實際上,它的易學性是離開Scala時公司的首要決定因素。
(6) 不變性
Scala對不可變數據結構(使用案例類)具有一流的支持。
(7) 空值
不利的一面是,Scala支持空引用。從好的方面來看,使用潛在缺失值的慣用方式是使用選項模式(就像其他功能語言一樣)。
(8) 錯誤處理
就像其他功能語言一樣,Scala習慣將Result模式用于錯誤處理。
(9) 并發
Scala在JVM之上運行,而JVM并不是真正為并發而構建的。從好的方面來說,Akka工具包非常成熟,并且在JVM上提供了類似于Erlang的并發。
(10) 模式匹配
Scala具有出色的模式匹配支持。
(11) 結論 3星
我真的很想喜歡Scala,但我不能。Scala嘗試做太多事情。為了同時支持OOP和FP,其設計人員必須做出很多權衡。正如俄羅斯諺語所說的那樣:"追趕兩只兔子的人一只都抓不到"。
Elm
Elm是一種功能強大的js編譯語言,主要用于前端Web開發。
Elm之所以與眾不同,是因為它承諾永遠不會出現運行時異常。用Elm編寫的應用程序非常強大。
語言家族:ML。
(1) 非常好的錯誤消息
Elm編譯器提供了我見過的一些最好的錯誤消息,這使該語言甚至對于初學者來說也更加容易上手。
(2) 錯誤處理
Elm如何處理錯誤?就像許多其他功能語言一樣,使用Resultdata類型。
(3) 函數純度
就像Haskell一樣,Elm是一種純函數式語言。
Elm是通過消除所有運行時異常來提高生產率,還是通過在所有地方強制執行功能純凈來使生產率降低?以我的經驗,在Elm中進行任何重大的重構都是一場噩夢,因為其中涉及大量的"管道"。
自己決定,但我會拒絕Elm的這一特性。
(4) 選項過于自以為是
> Quigglez on Reddit
Elm是一種自以為是的語言。到目前為止,使用制表符被視為語法錯誤。
Elm對"永遠不會出錯"的關注正在扼殺該語言。最新版本(0.19)引入了一項重大更改,這使得與JavaScript庫的互操作幾乎不可能。當然,這樣做的目的是讓人們在Elm中編寫自己的圖書館,以幫助生態系統發展。但是,很少有公司有資源來重新實現Elm中的所有功能。這使許多人永遠離開了Elm。
Elm的設計師似乎過于專注于函數純度,將"永無錯誤"的想法推向了極致。
(5) React沒有反應
Elm利用自己的虛擬DOM,與ReasonML等語言不同,它不使用React。這意味著開發人員無法訪問為React制作的龐大的庫和組件生態系統。
(6) 語言發展
遺憾的是,距離Elm的新版本(0.19.1)已經過去了一年多。開發流程的透明度為零,任何人都無法為開發做出貢獻。在每一個主要版本中,Elm都引入了重大更改,這使得某些語言無法使用。一年多來,我們從未真正聽到過其創建者的任何消息。我們甚至都不知道他是否仍在全職從事Elm。到現在,該語言可能實際上已經消失了。
(7) 模式匹配
Elm有很好的模式匹配支持。
(8) 不變性
Elm對不可變數據結構提供一流的支持。
(9) 空值
Elm不支持可為空的引用,就像其他函數式語言一樣,它使用Option模式。
(10) 結論 3.5星
Elm是一門出色的語言。不幸的是,它似乎沒有未來。但這可能是進入函數式編程的好方法。
F#
F#可以總結為.NET的OCaml。它的語法與OCaml非常相似,只是有一些細微的差別。F#于2005年首次出現,是一種非常成熟的語言,具有出色的工具和豐富的生態系統。
語言家族:ML。
(1) 類型系統
類型系統的唯一缺點是缺少高級類型。類型系統仍然非常牢固,編譯器能夠推斷出幾乎所有內容。F#對ADT具有適當的支持。
(2) 功能性,但不純粹
與Haskell / Elm不同,F#非常實用,并且不強制執行函數純度。
(3) 學習資源
F#有一些非常好的學習資源,可能與Elixir相當。
(4) 學習努力
F#是最容易使用的函數式語言之一。
(5) 生態
F#社區很小,與Elixir等語言不同,它根本沒有相同的強大庫。
(6) #C#互操作
從好的方面來說,F#可以訪問整個.NET / C#生態系統。與現有C#代碼互操作確實很好。
(7) 并發
F#在CLR之上運行,它沒有Elixir從Erlang VM中獲得的同樣出色的并發支持(稍后會詳細介紹)。
(8) 空值
F#代碼中通常不使用空值。它使用選項模式來表示可能不存在的值。
(9) 錯誤處理
慣用的F#代碼使用Result模式進行錯誤處理。
(10) 不變性
F#對不可變數據結構具有一流的支持。
(11) 模式匹配
F#具有強大的模式匹配支持。
(12) 結論 4星
F#是一種非常可靠的編程語言,具有非常好的類型系統。對于Web API開發,它幾乎與Elixir一樣好(稍后會詳細介紹)。但是,F#的問題不是它所擁有的,而是它所沒有的。為了與Elixir進行比較,其并發功能,豐富的生態系統和令人驚嘆的社區勝過F#提供的任何靜態鍵入好處。
· Dark的新后端將在F#中
(13) 獲獎情況
F#獲得了兩個獎項。
F#獲得了Fintech最佳語言獎。財務是F#的最大應用之一,這已經不是什么秘密了。
F#還獲得了企業軟件最佳語言獎。其豐富的類型系統允許對復雜的業務邏輯進行建模。強烈建議您閱讀《領域建模使功能》一書。
ReasonML
ReasonML是一種功能強大的js編譯語言,主要用于前端Web開發。
ReasonML不是一種新語言,它是OCaml(一種古老且嘗試過的編程語言)的新語法。ReasonML由Facebook支持。
通過利用JavaScript生態系統,ReasonML不會遭受與OCaml相同的弊端。
語言家族:ML。
(1) 不是JavaScript的超集
ReasonML的語法與JavaScript相似,這使具有JavaScript經驗的任何人都可以更容易地使用它。但是,與TypeScript不同,ReasonML甚至沒有嘗試成為JavaScript的超集(這是我們已經學到的一件好事)。與TypeScript不同,ReasonML不必繼承數十年來JavaScript做出的錯誤設計決策。
(2) 學習曲線
由于ReasonML甚至沒有嘗試成為JavaScript的超集,因此它使該語言比JavaScript簡單得多。具備JavaScript函數編程經驗的人可以在一周左右的時間內使用ReasonML。
ReasonML確實是最簡單的編程語言之一。
(3) 函數式,但不純粹
與Elm不同,ReasonML甚至沒有嘗試成為純函數式語言,也沒有"永遠不會出現運行錯誤"的目標。這意味著ReasonML非常實用,專注于開發人員的生產力,并快速實現結果。
(4) 類型系統
ReasonML實際上是OCaml,這意味著它的類型系統幾乎與Haskell一樣好。最大的缺點是缺少類型類,但它支持仿函數(高階模塊)。
ReasonML是靜態類型的,其類型推斷幾乎與Haskell一樣好。
(5) 生態
就像TypeScript一樣,ReasonML可以訪問整個JavaScript生態系統。
(6) JavaScript / TypeScript互操作
ReasonML編譯為純JavaScript。因此,可以在同一項目中同時使用ReasonML和JavaScript / TypeScript。
(7) ReasonML和React –天生一對
如果您正在進行前端Web開發,那么您很可能正在使用React。您知道嗎,React最初是用OCaml編寫的,然后才移植到JavaScript以幫助采用?
由于ReasonML是靜態類型的,因此無需擔心PropTypes。
還記得JavaScript一節中看起來很天真的示例,它可能導致性能下降嗎?
ReasonML對不可變數據結構提供了適當的支持,并且此類代碼不會產生性能問題:
與JavaScript不同,ReasonML無需重新渲染任何內容,即開即用的出色React性能!
(8) 工具
ReasonML尚未像TypeScript這樣的替代品那么成熟,并且該工具可能存在一些問題。例如,官方建議的VSCode擴展原因語言服務器當前已損壞,但是存在其他替代方法。
ReasonML在后臺使用OCaml編譯器,而OCaml則以非常糟糕的編譯器錯誤消息而聞名。雖然不是交易破壞者,但這有點令人沮喪,并且會影響開發人員的生產率。
我希望隨著語言的成熟,工具也會有所改進。
(9) 空值
ReasonML沒有空引用,并且使用Option模式來表示可能不存在的值。
(10) 不變性
ReasonML對不可變數據結構具有一流的支持。
(11) 模式匹配
ReasonML具有強大的模式匹配支持。
(12) 結論 4.5星
ReasonML可能是TypeScript一直以來的目標,但是失敗了。ReasonML將靜態類型添加到JavaScript,同時刪除所有不良功能(并添加真正重要的現代功能)。
(13) 最佳前端語言獎
最佳前端語言獎歸于ReasonML。毫無疑問,ReasonML是前端Web開發的最佳選擇。
Elixir
Elixir可能是世界上最受歡迎的函數式編程語言。就像ReasonML一樣,Elixir并不是真正的新語言。取而代之的是,Elixir建立在Erlang超過三十年的成功基礎上。
Elixir是Go的函數表親。與Go一樣,Elixir也是從頭開始設計的,用于并發以利用多個處理器內核。
與其他一些功能語言不同,Elixir非常實用。它專注于獲得結果。在Elixir社區中,您不會找到長時間的學術討論。Elixir論壇上充滿了針對實際現實問題的解決方案,社區對初學者非常友好。
語言家族:ML。
(1) 生態
真正使Elixir發光的是其生態系統。在大多數其他語言中,有兩種語言,然后是生態系統,這是兩個獨立的部分。在Elixir中,核心Elixir團隊正在開發生態系統中的核心框架。Elixir的創建者JoséValim還是Phoenix和Ecto(Elixir生態系統中的超酷庫)的主要貢獻者。
在大多數其他語言中,有多個不同的庫專注于同一任務-許多不同的Web服務器,許多不同的ORM等。在Elixir中,開發工作實際上集中在少數幾個核心庫上,這導致了出色的庫質量。
Elixir庫的文檔非常好,有很多示例。與某些其他語言不同,標準庫的文檔也很好。
(2) Phoenix框架
Phoenix框架的口號是" Phoenix感覺不錯"。與其他語言的框架不同,Phoenix具有許多內置功能。開箱即用,它支持WebSocket,路由,HTML模板語言,國際化,JSON編碼器/解碼器,無縫ORM集成(Ecto),會話,SPA工具包等。
Phoenix框架以其出色的性能而聞名,它能夠在一臺計算機上處理數百萬個同時連接。
(3) 全棧
Phoenix框架最近引入了LiveView,它允許在Elixir(認為單頁應用程序)內構建豐富的實時Web界面。無需JavaScript,無需React!
LiveView甚至負責同步客戶端和服務器狀態,這意味著我們不必擔心開發和維護REST / GraphQL API。
(4) 數據處理
對于許多與數據處理有關的任務,Elixir可以替代Python。在Python和Elixir中都構建了一個Web抓取工具之后,Elixir無疑是完成任務的更好的語言和生態系統。
諸如Broadway之類的工具允許在Elixir中構建數據提取/數據處理管道。
(5) 類型系統
我認為,缺少適當的靜態類型是Elixir的最大缺點。雖然Elixir不是靜態類型的,但編譯器(以及透析器)將在編譯時報告很多錯誤。與動態類型的語言(例如JavaScript,Python和Clojure)相比,這有很長的路要走。
(6) 速度
Elixir編譯器是多線程的,可提供極快的編譯速度。與Java虛擬機不同,Erlang VM快速啟動。對于Elixir的用例,運行時性能非常好。
(7) 可靠性
Elixir建立在Erlang之上,Erlang被使用了30多年來構建世界上最可靠的軟件。在Erlang VM上運行的某些程序已經能夠實現99.9999999%的可靠性。世界上沒有其他平臺可以擁有同等水平的可靠性。
(8) 并發
大多數其他編程語言尚未設計用于并發。這意味著編寫使用多個線程/處理器內核的代碼絕非易事。其他編程語言使用執行并行代碼(和共享內存,線程從中讀取/寫入)的線程。這種方法通常容易出錯,容易出現死鎖,并導致復雜度成指數增長。
Elixir建立在以其出色的并發功能而聞名的Erlang之上,并采用了一種完全不同的并發方法,稱為actor模型。在此模型中,流程(參與者)之間沒有任何共享。每個進程都維護自己的內部狀態,并且各個進程之間進行通信的唯一方法是發送消息。
順便說一下,參與者模型實際上是其創建者Alan Kay最初打算使用的OOP,其中沒有任何共享,對象僅通過傳遞消息進行通信。
讓我們快速比較一下Elixir和它的命令表親Go。與Go不同,Elixir完全是為容錯而設計的。每當goroutine崩潰時,整個Go程序都會關閉。在Elixir中,每當一個進程死亡時,只有那個單個進程死亡,而不會影響程序的其余部分。更好的是,失敗的進程將由其主管自動重啟。這允許失敗的進程重試失敗的操作。
Elixir的流程也非常輕巧,可以在一臺機器上輕松運行數十萬個流程。
(9) 縮放
讓我們再與Go進行比較。Go和Elixir中的并發利用并發進程之間的消息傳遞。由于Go可以編譯為本地代碼,因此Go程序將在第一臺計算機上運行得更快。
但是,一旦您開始擴展到第一臺機器之外,Go程序就會開始丟失。為什么?因為Elixir是從頭開始設計的,因此可以在多臺機器上運行。當涉及到分發和擴展時,Elixir在其之上運行的Erlang VM確實令人眼前一亮。它無縫地處理了許多繁瑣的事情,例如集群,RPC功能和網絡。
從某種意義上說,Erlang VM在微服務成為現實之前就已經在進行微服務了。每個進程都可以視為微服務-就像微服務一樣,進程彼此獨立。通過語言內置的通信機制,進程可以跨多臺機器運行的情況并不少見。
沒有Kubernetes復雜性的微服務?檢查一下這就是Elixir真正設計的目的。
(10) 錯誤處理
Elixir采用非常獨特的方法來處理錯誤。盡管純函數式語言(Haskell / Elm)旨在最大程度地減少錯誤發生的可能性,但Elixir認為錯誤不可避免地會發生。
在Elixir中,拋出異常很好,而通常不建議捕獲異常。相反,流程主管將自動重新啟動失敗的流程,以保持程序運行。
(11) 學習曲線
Elixir是一種簡單的語言,人們可以在大約一兩個月后拿起Elixir。使學習變得有些困難的是OTP。
OTP是Elixir的"殺手feature"。OTP是Elixir構建的Erlang的一組工具和庫。正是"秘密調味料"極大地簡化了構建并發和分布式程序的過程。
盡管Elixir本身很簡單,但將頭纏在OTP上可能要花費一些時間,但這確實對我有用。
(12) 學習資源
作為最受歡迎的函數式編程語言,Elixir具有豐富的學習資源。關于實用程序程序員,有許多驚人的Elixir書。學習資源幾乎總是對初學者非常友好。
(13) 模式匹配
Elixir具有出色的模式匹配支持。
(14) numbers運算數字
Elixir無法很好地處理計算密集型任務。對于此類任務,應選擇本機編譯語言(Go / Rust是不錯的選擇)。
(15) 好吧,和Erlang有什么關系?
出于所有意圖和目的,Elixir和Erlang完全相同。Erlang是一種功能強大的語言,具有奇怪的語法。Elixir可以被認為是Erlang的一種更好,更現代的語法(以及非常好的生態系統和社區)。
(16) 結論 4.5星
Elixir可能是所有函數式語言中最成熟的。它還在用于功能編程的虛擬機之上運行。它是專為并發而設計的,非常適合現代多核處理器時代。
(17) 獲獎情況
Elixir獲得兩個獎項。
它的彈性,函數至上的方法和令人驚嘆的生態系統使其成為構建Web API的最佳語言。
OTP和參與者模型使Elixir成為構建并發和分布式軟件的最佳語言。與命令式表弟Go不同,用Elixir編寫的軟件可以水平擴展到數千臺服務器,并且具有開箱即用的容錯能力。
為什么不使用正確的工具進行工作?
> Photo by Haupes Co. on Unsplash
你會用螺絲刀打釘嗎?可能不會。然后,我們可能不應該嘗試對所有內容都使用一種編程語言,每種語言都有自己的位置。
Go是用于系統編程的最佳語言。前端開發的最佳選擇無疑是ReasonML,它滿足了出色編程語言的大多數要求。Web API開發的絕對贏家是Elixir,它的唯一缺點是缺少靜態類型系統(它被強大的生態系統,社區,可靠性和并發功能所抵消)。對于任何種類的并發/分布式軟件,最好的選擇還是Elixir。
如果你正在從事數據科學工作,那么不幸的是,唯一合理的選擇是Python。
我真的希望這篇文章有用。比較編程語言絕非易事,但我已盡力而為。