11

那些让码农倍感痛苦的现代编程语言

 3 years ago
source link: http://developer.51cto.com/art/202012/634613.htm
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

特定编程语言的优缺点是什么?X是我的任务很好的语言吗?搜寻"最佳编程语言"将为您提供" Python,Java,JavaScript,C#,C ++,PHP"的标准列表,以及优缺点的模糊列表。看到这样的文章会让我感到痛苦,他们的作者一定是完全懒惰,缺乏经验,同时又缺乏想象力。让我们深入研究一下,找出真正的缺点,而不是什么。

y6jQjuF.jpg!mobile

在本文中,我将尝试对流行的(而不是那么流行的)现代编程语言进行客观,公正的概述,从最坏到最好的排名。

请记住,没有一种编程语言可以完美地适合所有可能的用例。一些语言最适合于前端开发,其他语言最适合于后端/ API开发,其他语言则非常适合系统编程。

我将介绍世界上两个最常见的语言家族-语言是C衍生的,而语言是ML衍生的。

编程语言只是开发人员工具箱中的工具。选择正确的工具来完成这项工作很重要。我真的希望本指南将帮助您选择最适合您任务的编程语言。做出正确的选择可以节省您数月(甚至数年)的开发工作。

哪些语言特征真正重要?

ZZVVRvi.jpg!mobile

大多数其他类似的文章都根据受欢迎程度和潜在收入等因素进行比较。受欢迎程度很少是一个很好的衡量标准,尤其是在软件领域(尽管大型社区和生态系统会有所帮助)。相反,我将考虑特定语言的优点和缺点。

我将使用大拇指(即+1),大拇指朝下或OK(无论好坏)表情符号来表示特定语言特征的得分。

现在,我们将如何衡量?换句话说,除了语言流行之外,真正重要的是什么?

一、类型系统

vQzaiiR.jpg!mobile

许多人按类型系统发誓。因此,近年来诸如TypeScript之类的语言开始流行。我倾向于同意,类型系统消除了程序中的大量错误,并使重构更加容易。但是,"拥有"类型系统只是故事的一部分。

如果语言具有类型系统,那么进行类型推断也非常有用。最好的类型系统能够推断大多数类型,而无需显式注释功能签名。不幸的是,大多数编程语言仅提供基本的类型推断。

对于类型系统来说,支持数字数据类型也很好(稍后会详细介绍)。

最强大的类型系统支持高级类型,这是泛型之上的抽象级别,并允许我们以更高的抽象级别进行编程。

我们还必须记住,人们往往对类型系统过于重视。有些事情远比静态类型重要,选择类型时,类型系统的存在与否并不是唯一的因素。

(1) 学习曲线

IRNB737.jpg!mobile

我们可能拥有完美的编程语言,但是如果新入职的开发人员可能要花费数月甚至数年(前期投资)来学习,它将有什么用?另一方面,某些编程范例需要花费数年才能变得精通。

一门好的语言应该适合初学者,并且不需要花几年的时间就能掌握。

(2) 空值

jmyUzqI.jpg!mobile

-空引用的发明者托尼·霍尔(Tony Hoare)

为什么空引用不好?空引用中断类型系统。当null为默认值时,我们将不再依赖编译器来检查代码的有效性。任何可为空的值都是等待爆炸的炸弹。如果我们尝试使用我们不认为可能为空但实际上为空的值怎么办?我们得到一个运行时异常。

我们必须依靠手动运行时检查来确保所处理的值不为null。即使使用静态类型的语言,空引用也剥夺了类型系统的许多好处。

实际上,这种运行时检查(有时称为空防护)是针对不良语言设计的解决方法。他们用样板乱码。最糟糕的是,我们无法保证不会忘记检查null。

用一种好的语言,应该在编译时检查值的缺失或存在。

鼓励使用其他机制处理缺失数据的语言将排名更高。

(3) 错误处理

BvAZr2v.png!mobile

捕获异常是处理错误的一种坏方法。抛出异常是可以的,但仅在例外情况下,程序无法恢复并且必须崩溃。就像空值一样,异常会破坏类型系统。

当使用异常作为错误处理的主要方式时,就无法知道函数是返回期望值还是崩溃。引发异常的函数也是不可能组成的。

显然,仅仅由于我们无法获取某些数据而导致整个应用程序崩溃是不可能的。但这确实比我们想要的更经常发生。

一种选择是手动检查引发的异常,但是这种方法很脆弱(我们可能会忘记检查异常),并且会增加很多噪音:

如今,有更好的错误处理机制,可能的错误应在编译时进行类型检查。默认情况下不使用例外的语言将排名更高。

(4) 并发

3A3YvqN.png!mobile

我们已经到了摩尔定律的尽头,处理器将不会更快。我们生活在多核CPU时代,实际上,任何现代应用程序都必须利用多核。

不幸的是,当今使用的大多数编程语言都是在单核计算时代设计的,根本不具备可在多核上有效运行的功能。

帮助并发的库是事后的想法,它们只是向最初不是为并发设计的语言添加了创可贴。这并不是真正的良好开发经验。在现代语言中,必须内置并发支持(请考虑使用Go / Erlang / Elixir)。

(5) 不变性

aiqY3qI.png!mobile

— Clojure的创建者Rich Hickey。

如今,使用不变的值进行编程变得越来越流行。甚至像React这样的现代UI库也打算与不可变值一起使用。具有对不可变数据值的一流支持的语言将排名更高。仅仅因为不变性消除了我们代码中的一整类错误。

什么是不可变状态?简而言之,它是不变的数据。就像大多数编程语言中的字符串一样。例如,大写字符串永远不会更改原始字符串-始终会返回一个新字符串。

不变性进一步推动了这一想法,并确保一切都没有改变。总会返回一个新数组,而不是更改原始数组。更新用户名?将返回一个新的用户对象,并更新其名称,同时保留原始对象。

处于不可变状态时,不会共享任何内容,因此我们不再需要担心线程安全性的复杂性。不变性使我们的代码易于并行化。

不改变任何状态的函数称为纯函数,它们很容易测试和推理。使用纯函数时,我们不必担心函数之外的任何事情。只需专注于正在使用的这一函数,而忽略其他所有函数。你可能可以想象,开发变得多么容易(与OOP相比,必须牢记整个对象图)。

(6) 生态系统/工具

nURBbm3.png!mobile

语言可能不是很好,但是它可能具有庞大的生态系统,因此很有吸引力。访问优质的库可以节省一个月(甚至几年)的开发工作。

我们已经看到JavaScript和Python等语言会发生这种情况。

(7) 速度

77BzYfR.png!mobile

语言的编译速度如何?程序启动速度有多快?运行时性能如何?所有这些都很重要,并将列入排名。

(8) 年龄

YFrI7fm.png!mobile

尽管有一些例外,但通常来说,较新的语言会比较旧的语言更好。仅仅因为更新的语言可以从其前辈的错误中学习。

二、C ++

fiayqmU.png!mobile
eABrU33.png!mobile

让我们从最坏的情况入手,这可能是计算机科学中最大的错误之一,C ++。是的,C ++不被认为是一种崭新的现代编程语言。但是今天它仍在广泛使用,必须将其包括在列表中。

语言家族:C.

(1) 语言功能

INf2YnF.jpg!mobile

C ++是一种可怕的语言……而且将项目限制为C意味着人们不会用任何愚蠢的"对象模型" c&@ p弄乱事情。— Linux的创建者Linus Torvalds。

C ++具有许多功能。它尝试做所有事情,同时又不擅长任何特定的事情。C ++具有goto,指针,引用,OOP,运算符重载和许多其他非生产性功能。

为什么C ++如此糟糕?我认为,最大的原因是它的年龄。C ++是在1979年设计的很早的时候。当时的设计师缺乏经验,也不知道该关注什么。当时添加的功能似乎是个好主意。该语言非常流行,这意味着添加了许多功能来支持各种用例(创建更大的功能混乱)。

(2) 速度

C ++因其编译时间慢而臭名昭著。比Java慢得多,不如Scala。

但是,运行时性能以及启动时间都很好。

(3) 生态/工具

zq6vear.png!mobile

以上推文很有意义。C ++编译器

(4) 垃圾收集

-C ++的创建者Bjarne Stroustrup

垃圾回收从未添加到C ++中。手动内存管理极易出错。开发人员必须担心手动释放和分配内存。我将永远不会错过使用非垃圾收集语言的日子,如今在垃圾收集语言中很容易避免许多错误。

(5) attempt失败的面向对象编程尝试

-Alan Kay,面向对象编程的发明者。

OOP出现于60年代后期,是C ++工作开始时的一项很酷的新技术。不幸的是,C ++在实现OOP时犯了一些关键错误(与Smalltalk等语言不同),这使一个好主意变成了一场噩梦。

与Java相比,C ++的一件好事是C ++中的OOP至少是可选的。

(6) 学习曲线

jI7Vbam.png!mobile

> Mercurial_Rhombus on Reddit

C ++是一种复杂的低级语言,没有自动内存管理。由于其功能膨胀,初学者不得不花很多时间学习该语言。

(7) 并发

C ++是在单核计算时代设计的,在过去的十年中仅添加了基本的并发机制。

(8) 错误处理

捕获/抛出错误是首选的错误处理机制。

(9) 不变性

没有对不可变数据结构的内置支持。

(10) 空值

在C ++中,所有引用都是可为空的。

(11) 结论0.5星

2qiARz7.png!mobile

最初旨在成为C的更好版本的C ++确实未能实现目标。

C ++的最佳用途可能是系统编程。但是,鉴于存在更好,更现代的替代方案(Rust and Go),C ++甚至不应该用于此。我认为C ++毫无优势,请随时证明我是错的。

C ++,你该走了。

三、Java

YNBvyae.png!mobile

BfmeQbZ.png!mobile

-Alan Kay,面向对象编程的发明者。

自1995年首次出现以来,Java比C ++年龄小16岁。Java是一种简单得多的语言,这可能有助于其流行。

语言家族:C.

(1) 垃圾收集

Java提供的优于C ++的最大好处之一是垃圾收集,垃圾收集本身消除了许多错误。

(2) 生态

Java已经存在了很长时间,并且它具有一个庞大的用于后端开发的生态系统,从而大大减少了开发工作。

(3) 面向对象语言

在这里,我不会深入探讨OOP的缺点,有关更详细的分析,可以阅读我的其他文章《面向对象编程—万亿美元灾难》。

相反,我只是引用一些计算机科学领域最杰出的人,以得到他们对OOP的看法:

很抱歉,我很久以前就为该主题创造了"对象"一词,因为它使许多人专注于较小的想法。大想法是消息传递。

-OOP的发明者艾伦·凯(Alan Kay)

艾伦·凯(Alan Kay)是对的,主流的OOP语言专注于错误的事物(类和对象),而忽略了消息传递。值得庆幸的是,现代语言正确地实现了这个想法(Erlang / Elixir)。

—理查德·曼斯菲尔德(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星

BfmeQbZ.png!mobile

Java出现时是一种不错的语言。太糟糕了,Java(与Scala不同)一直只专注于OOP。该语言非常冗长,并且受样板代码的影响很大。

Java退休的时候到了。

四、C#

vaMz22b.png!mobile

2EbaIrR.png!mobile

从根本上讲,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星

RbIVjie.png!mobile

我在C#的职业生涯中花费了大量时间,并且总是对这种语言感到沮丧。与Java一样,我建议您寻找更现代的替代方案。它是相同的Java,但语法更现代。

不幸的是,关于C#并没有什么"尖锐"的东西。

Python

qeaI7fv.png!mobile

bea6f27.png!mobile

自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星

IFfAj2F.png!mobile

真的很不幸,Python没有对函数式编程的适当支持。函数式编程非常适合于数据科学试图解决的问题。即使对于诸如网络抓取之类的非常Python的任务,函数式语言(例如Elixir)也更合适。

我不建议将Python用于大型项目,因为该语言在构建时并未考虑到严格的软件工程。

当没有其他替代方法可用时,Python不应用于数据科学以外的其他任何用途。在数据科学领域,Julia似乎是Python的一个很好的现代替代品,尽管它的生态系统还不如Python成熟。

Rust

yMFjQra.png!mobile

bea6f27.png!mobile

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星

bea6f27.png!mobile

Rust非常适合系统编程。尽管它比Go更复杂,但它提供了强大的类型系统。Rust为空值提供了一种现代的替代方法,并提供了一种处理错误的现代方法。

为什么Rust仍然排名低于TypeScript和JavaScript?它是为系统编程设计的低级语言。Rust并非非常适合后端/ Web API开发。它缺少垃圾收集,并且不内置对不变性的支持。

TypeScript

YZraiq.png!mobile

vEZjMvU.png!mobile

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 — 地狱般的匹配吗?

-直接来自React文档

延续先前的缺点,如果你正在进行前端Web开发,那么你很可能正在使用React。

未为TypeScript创建React。最初,React是针对功能性语言编写的(稍后会详细介绍)。编程范例之间存在冲突-TypeScript是OOP优先,而React是功能优先。

React希望其props(即函数参数)是不可变的,而TypeScript没有对不可变数据结构的适当内置支持。

TypeScript通过JavaScript提供给React开发的唯一真正好处是,不必担心PropTypes。

(9) 是TypeScript还是Hypescript?

FvEfqij.png!mobile

TypeScript只是一种炒作吗?由你决定。我认为是这样。它的最大好处是可以访问整个JavaScript生态系统。

为什么HypeScript如此受欢迎?Java和C#受欢迎的原因相同-得到数十亿公司的庞大营销预算的支持。

(10) 结论 2星

vEZjMvU.png!mobile

尽管通常认为TypeScript是"更好的JavaScript",但我认为它比JavaScript低。它提供的超过JavaScript的好处被高估了,特别是对于使用React进行前端Web开发。

TypeScript确实无法通过保留JavaScript的所有不良部分来交付,实际上无法继承JavaScript中数十年的不良设计决策。

Go

nIRFFna.png!mobile

EbU7ren.png!mobile

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) 类型系统

mu6VrmA.png!mobile

几乎每种现代编程语言都有一种或另一种形式的泛型(包括可怕的C#/ Java,甚至C ++都有模板)。泛型允许开发人员针对不同类型重用函数实现。如果没有泛型,则必须分别为整数,双精度数和浮点数分别实现add函数,从而导致大量代码重复。换句话说,Go中缺少泛型会导致大量重复代码。有人说," Go"是" Go写一些样板"的缩写

(8) 空值

不幸的是,数十年来,更安全的替代方法已经出现,Go语言包含了空值。

(9) 不变性

Go没有对不可变数据结构的内置支持。

(10) 结论 2.5星

yAzeau6.png!mobile

-雅格(Will Yager)的《为什么Go不好》

如果你不是Google,并且没有类似Google的用例,那么Go可能不是一个好选择。Go是最适合系统编程的一种简单语言。对于API开发,Go不是一个好的选择(原因是因为有很多更好的选择可用,稍后再介绍)。

我认为总体而言,Go是一个比Rust更好的选择(尽管类型系统较弱)。它是一种简单的语言,非常快,易于学习并且具有出色的并发功能。是的,Go成功实现了成为"更好的C ++"的设计目标。

(11) 最佳系统语言奖

3EZbUbm.png!mobile

最佳系统语言奖归Go。毫无疑问,Go是系统编程的理想选择。Go是一种低级语言,它非常适合该领域,这已被大量使用Go构建的成功项目所证实,例如Kubernetes,Docker和Terraform。

JavaScript

2yQz2az.png!mobile

EbU7ren.png!mobile

作为世界上最受欢迎的编程语言,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 星

yAzeau6.png!mobile

JavaScript不是一种精心设计的语言。JavaScript的初始版本在10天内就放在一起了(尽管将来的版本已经解决了许多缺点)。

尽管有缺点,JavaScript是全栈Web开发的不错选择。通过适当的纪律和评价,JavaScript可以成为一门好语言。

函数式编程==放心

MzQrQvb.jpg!mobile

> Photo by Ante Hamersmit on Unsplash

让我们先绕道而行,然后再继续排名。为什么要烦恼函数式编程?函数式编程使我们高枕无忧。

是的,函数式编程可能听起来很吓人,但实际上没有什么可担心的。简而言之,函数式语言做出了许多正确的设计决策,而其他语言则做出了错误的决策。在大多数情况下,函数式语言将具有正确的功能:具有代数数据类型支持的功能强大的类型系统,无null,错误处理无异常,内置的不变数据结构,模式匹配,函数组合运算符。

函数式编程语言有哪些共同的优势使其在我们的排名中如此高?

(1) 使用纯函数编程

U3qUJvZ.png!mobile

与命令式(主流语言)不同,函数式编程语言鼓励使用纯函数式编程。

什么是纯函数?这个想法非常简单-给定相同的输入,纯函数将始终返回相同的输出。例如,2 + 2将始终返回4,这意味着加法运算符+是纯函数。

纯函数不允许与外界进行交互(进行API调用,甚至无法写入控制台)。甚至不允许更改状态。这与OOP所采取的方法完全相反,在OOP中,任何方法都可以自由地改变其他对象的状态。

可以很容易地从不纯函数中分辨出纯函数-函数是不带参数,还是不返回值?然后,这是一个不纯函数。

这种方法似乎很局限,可能需要一段时间才能习惯。起初,这肯定让我感到困惑!

纯函数有什么好处?它们非常易于测试(无需模拟和存根)。关于纯函数的推理很容易-与OOP不同,无需牢记整个应用程序状态。您只需要担心当前正在使用的功能。

纯函数可以轻松组成。纯函数对于并发非常有用,因为函数之间没有共享状态。重构纯函数是纯粹的乐趣-只需复制和粘贴,无需复杂的IDE工具。

简而言之,纯函数将欢乐带回到编程中。

函数式编程鼓励使用纯函数-当90%以上的代码库由纯函数组成时,这很好。一些语言将其极端化,并完全禁止使用非纯函数(这并不总是一个好主意)。

(2) 不变的数据结构

fYbi2ue.png!mobile

下面的所有功能语言都内置了对不可变数据结构的支持。数据结构也是持久的。这只是意味着,无论何时进行更改,我们都不必创建整个结构的深层副本。一次又一次地成像复制超过100,000个项目的阵列,这一定很慢,对吧?

持久数据结构无需创建副本,而是简单地重用对旧数据结构的引用,同时添加所需的更改。

(3) 数值数据类型

qaamAni.png!mobile

ADT是一种建模应用程序状态的强大方法。可以将它们视为类固醇的枚举。我们指定类型可以组成的可能的"子类型",以及其构造函数参数:

上面的"形状"类型可以是正方形,矩形或圆形。Square构造函数采用单个int参数(宽度),Rectangle采用两个int参数(宽度和高度),而Circle采用单个int参数(其半径)。

我不了解你,但我肯定会使用旧版本,并以功能语言使用ADT。

(4) 模式匹配

zAFRJn2.png!mobile

所有功能语言都对模式匹配提供了极大的支持。通常,模式匹配允许人们编写非常有表现力的代码。

这是一个关于选项(布尔)类型的模式匹配的示例:

相同的代码,没有模式匹配:

毫无疑问,模式匹配版本更加富有表现力和简洁。

模式匹配还提供了编译时的详尽性保证,这意味着我们将不会忘记检查可能的情况。没有以非功能性语言提供的此类保证。

(5) 空值

77NB3av.png!mobile

函数式编程语言通常避免使用空引用。而是使用Option模式(类似于Rust):

(6) 错误处理

BvAZr2v.png!mobile

通常不建议在功能语言中使用异常。而是使用Result模式(再次,类似于Rust):

要全面了解错误处理的功能方式,请确保阅读OCaml中的Composable Error Handling。

(7) 管道前移运算符

vmmAJ33.png!mobile

如果没有管道前移运算符,函数调用往往会变得很嵌套,这使它们的可读性降低:

函数式语言具有特殊的管道运算符,使该任务更加容易:

ZVzyE3Q.png!mobile

euEB32v.png!mobile

(8) Huskell

语言家族:ML。

(9) 类型系统

没有比Haskell更强大的文字系统了。显然,Haskell支持代数数据类型,但它也支持类型类。它的类型检查器几乎可以推断任何东西。

(10) 学习曲线

好家伙!为了有效地使用Haskell,必须首先精通类型理论(这不是我在开玩笑),这不是秘密。OOP需要多年的经验来编写体面的代码,而Haskell则需要投入大量时间进行前期学习,才能提高生产力。

在Haskell中编写甚至一个简单的" hello world"程序也需要了解Monads(尤其是IO Monads)。

(11) 社区

根据我的经验,Haskell社区的学术性更高。最近在Haskell库邮件列表中的帖子开始于:

它收到了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星

fIZfUzB.png!mobile

-David Bryant Copeland获得了四个更好的软件设计规则

我真的很想喜欢Haskell。不幸的是,Haskell可能会永远局限于学术界。Haskell是函数式编程语言中最糟糕的吗?我认为是你来决定的。

OCaml

N3UN3a.png!mobile

fIZfUzB.png!mobile

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星

fIZfUzB.png!mobile

OCaml是一种很好的函数式语言。它的主要缺点是并发支持差,社区很小(因此生态系统很小,缺乏学习资源)。

鉴于其缺点,我不建议在生产中使用OCaml。

· 离开OCaml

Scala

7FfyQjM.png!mobile

euEB32v.png!mobile

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星

fIZfUzB.png!mobile

我真的很想喜欢Scala,但我不能。Scala尝试做太多事情。为了同时支持OOP和FP,其设计人员必须做出很多权衡。正如俄罗斯谚语所说的那样:"追赶两只兔子的人一只都抓不到"。

Elm

VjyimmJ.png!mobile

b6nIJjZ.png!mobile

Elm是一种功能强大的js编译语言,主要用于前端Web开发。

Elm之所以与众不同,是因为它承诺永远不会出现运行时异常。用Elm编写的应用程序非常强大。

语言家族:ML。

(1) 非常好的错误消息

Elm编译器提供了我见过的一些最好的错误消息,这使该语言甚至对于初学者来说也更加容易上手。

(2) 错误处理

Elm如何处理错误?就像许多其他功能语言一样,使用Resultdata类型。

(3) 函数纯度

就像Haskell一样,Elm是一种纯函数式语言。

Elm是通过消除所有运行时异常来提高生产率,还是通过在所有地方强制执行功能纯净来使生产率降低?以我的经验,在Elm中进行任何重大的重构都是一场噩梦,因为其中涉及大量的"管道"。

自己决定,但我会拒绝Elm的这一特性。

(4) 选项过于自以为是

UbEbq2.png!mobile

> 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星

beiqAb.png!mobile

Elm是一门出色的语言。不幸的是,它似乎没有未来。但这可能是进入函数式编程的好方法。

F#

fIjEZzU.png!mobile

zeiAvub.png!mobile

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星

zeiAvub.png!mobile

F#是一种非常可靠的编程语言,具有非常好的类型系统。对于Web API开发,它几乎与Elixir一样好(稍后会详细介绍)。但是,F#的问题不是它所拥有的,而是它所没有的。为了与Elixir进行比较,其并发功能,丰富的生态系统和令人惊叹的社区胜过F#提供的任何静态键入好处。

· Dark的新后端将在F#中

(13) 获奖情况

eeqyEfy.png!mobile

F#获得了两个奖项。

F#获得了Fintech最佳语言奖。财务是F#的最大应用之一,这已经不是什么秘密了。

F#还获得了企业软件最佳语言奖。其丰富的类型系统允许对复杂的业务逻辑进行建模。强烈建议您阅读《领域建模使功能》一书。

ReasonML

ZBnuAvu.png!mobile

MZNVjuq.png!mobile

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星

MZNVjuq.png!mobile

ReasonML可能是TypeScript一直以来的目标,但是失败了。ReasonML将静态类型添加到JavaScript,同时删除所有不良功能(并添加真正重要的现代功能)。

(13) 最佳前端语言奖

aA7naqz.png!mobile

最佳前端语言奖归于ReasonML。毫无疑问,ReasonML是前端Web开发的最佳选择。

Elixir

INz6fuf.png!mobile

MZNVjuq.png!mobile

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星

MZNVjuq.png!mobile

Elixir可能是所有函数式语言中最成熟的。它还在用于功能编程的虚拟机之上运行。它是专为并发而设计的,非常适合现代多核处理器时代。

(17) 获奖情况

6RrEnym.png!mobile

Elixir获得两个奖项。

它的弹性,函数至上的方法和令人惊叹的生态系统使其成为构建Web API的最佳语言。

OTP和参与者模型使Elixir成为构建并发和分布式软件的最佳语言。与命令式表弟Go不同,用Elixir编写的软件可以水平扩展到数千台服务器,并且具有开箱即用的容错能力。

为什么不使用正确的工具进行工作?

j6V3ain.jpg!mobile

> Photo by Haupes Co. on Unsplash

你会用螺丝刀打钉吗?可能不会。然后,我们可能不应该尝试对所有内容都使用一种编程语言,每种语言都有自己的位置。

Go是用于系统编程的最佳语言。前端开发的最佳选择无疑是ReasonML,它满足了出色编程语言的大多数要求。Web API开发的绝对赢家是Elixir,它的唯一缺点是缺少静态类型系统(它被强大的生态系统,社区,可靠性和并发功能所抵消)。对于任何种类的并发/分布式软件,最好的选择还是Elixir。

如果你正在从事数据科学工作,那么不幸的是,唯一合理的选择是Python。

我真的希望这篇文章有用。比较编程语言绝非易事,但我已尽力而为。

【责任编辑:赵宁宁 TEL:(010)68476606】


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK