各编程语言设计哲学
各编程语言设计哲学
就拿现在 TIOBE Index 这垃圾榜单从上到下说。
Python 的哲学是“唯一一种方式实现唯一一种场景”,崇尚简洁。
C 的哲学是精简语法,直接对应汇编,把汇编伪装成高级语言。
C++的哲学是零成本抽象,提供一套啥都有的工具箱,但不考虑学习成本。
Java 的哲学是屏蔽复杂性,保证语言简单和高可维护性,并保证尽可能的高性能,但语法好不好看、冗不冗长就无所谓了。
C#的哲学是使用面向对象的思路,但与 Java 不同,它试图让功能尽可能强大,给程序员充分的自由度,但对于危险的用法要制造一些阻碍,比如用 unsafe 来提示程序员当前写的代码很危险,同时又要保证高性能,并且维持优美的语法设计,提供一定量的语法糖,某种意义上既是 Better Java 又是 Best Practice C++,唯一的槽点是它有个微软爹。
VB 虽然喷了十几年,但它也是有自己的哲学的,就是简单、图形化界面,开发客户端很快。
JS 的核心是 Self 的那套逻辑,哲学就是维持语言的简单,其本质是函数式的,但又要装得很像 Java,我的评价是脑子有病,但用起来莫名其妙很舒服。
SQL(如果这也是编程语言的话)的哲学是声明式语法,用关系代数描述操作,不用关心底层实现。
ASM 的哲学就是直接对应机器执行,这没啥好说的。
PHP 的哲学是实用玩屎主义,突出一个糙猛快,烂的很有特色,但是 PHP 8 和现在 Laravel 之类的现代化框架奇迹般地把屎给抹平了,把 PHP 变成了另一门语言强行续命,虽然还是无法阻挡地大势已去。
Go 的哲学是“大道至简”,实际上就是简陋和类型不安全,但 Go 社区总是很自信,不觉得自己有什么问题。
R 的哲学就是尽一切可能让数据科学工作者用起来舒服,比如它丰富的内置函数和向量化运算,其实 NumPy 很大程度上借鉴了 R,平心而论我还挺喜欢 R 的,当然它是不会考虑 R 包开发者的痛苦和正经程序员使用起来的难受的,不过和 PHP 类似,这东西也有 tidyverse 强行给它续命,导致一时半会还不会死,甚至能活得更好。
Matlab 的哲学就是适应物理工作者的需求,丰富的文档,极多的内置函数,原生的矩阵支持,友好的画图 API,一大堆工具箱开箱即用,都使 Matlab 即使面对 Python 的冲击仍在工学领域有不可替代的优势。
Delphi 的哲学其实是 Pascal 的哲学。Pascal 的哲学是优美与严谨,带点学院派气质,真的很美好,可以看到很多算法书上的伪代码和 Pascal 极其类似,或许也有这方面的影响。整洁而优美,但是学术气太重,作为一门本来就是用来教学的语言,它承担了不该承担的开发任务。而且也生错了时代,语法啰嗦,这在当时没 IDE 的时代是个问题,现在已经不是了,很遗憾。
Swift 的哲学就是现代化,又让程序员写得舒服。Swift 是近十几年出的语言里我最喜欢的一门,优美而实用。其实某种意义上,Swift 类似于 Better C#,它有历史教训,引入了很多现代化的东西,语言设计非常自洽,比如设计良好的 Checked Exception、Actor、Nullable Safety 等。可惜 Swift 虽然优美,但本身复杂度也很高,上手其实很困难,而且之前许多个版本疯狂不向前兼容的行为引来了很多恶名。在这方面,它有点像 Scala,只是学院气稍微少点。还有个问题,它摊上了一个苹果爹,和 C#一样不幸。但反过来说,如果不是苹果,也不会开发个 Swift 出来。所以现在 Swift 是大家都说好,每门语言都在抄,但除了 iOS 开发者没人在用,生态也很差。
Ruby 的哲学很简单,快乐编程嘛。到处都是语法糖,一个问题有几十上百种不同的方案解决!极端自由,想怎么写就怎么写。一个人写很开心,RoR 开发速度也飞快,开发效率爆炸。缺点是两个人写的时候,就开始不行了,但团队大于三个人,Ruby 的自由变成了严重的缺陷。但我还是喜欢 Ruby,因为很自由。
Perl 其实就是可以说是前 Ruby,设计哲学也是让程序员用得爽,不过稍微有点区别。Perl 自己不是特别在乎可读性,喜欢用一堆鬼画符来减少敲字的数量,这在现在这个 IDE 时代就没啥优势了,但在前 IDE 时代这一特性让 Perl 写着很爽又很快。另一点是在 Perl 中正则表达式完全嵌入了语言本身,在字符串处理这块应该仍旧没有任何语言比得上 Perl——但问题是,现在还有什么应用会为了一个字符串处理上的优势而选择啥都不行了的 Perl 呢?除此之外,Perl 三种类型的变量也是个设计时拍脑袋觉得很好,使用体验却不太好的东西,有很多原始的地方。
Scratch——我不知道 TIOBE 抽什么疯,这东西能排进前二十。这有啥好说的,Scratch 甚至不是一门编程语言,它是个给小朋友玩的玩具。
Classic VB——评价同上边的 VB.net。
Rust——总算挤进前二十了。Rust 的哲学和 C++一样是零成本抽象,无 GC,但想办法优化了 C++的安全性,不允许不安全的代码编译通过,于是从根本上杜绝了垃圾代码的出现。同时 Rust 相当受函数式编程语言及一些 PL 界的理论工作影响,有很多学术性的东西加到了里面,其实相当先进。但 Rust 也做了一些妥协,为了降低学习成本,把语法搞得比较乏味,不是很具有创新性——当然,这只是稍微降低了一点学习成本,毕竟生命周期和所有权本身就不是好理解的东西。
由于 TIOBE 过于神秘,很多应该排上去的语言不在前二十。下面让我们快速过一下前二十一到五十的语言。
SAS、FoxPro 不是正常的编程语言,不提了。
Ada,Pascal 系的语言,所以和 Pascal 一样的结局……作为当初的美国军用语言,它在编译期做了更多工作,例如使用 Natural 表示自然数,而不是更宽泛的 Integer。理所当然,Ada 没人用了,因为美国军方发现找不到 Ada 程序员。
Fortran 其实没什么哲学可言,作为当年第一门真正意义上的高级语言,它的目的就只是让人们摆脱汇编而已。在这一点上,它做的很好,但也早该被淘汰了。
Lisp 的哲学是手写 AST,一切都是宏,语言即数据,以简单的语法造就高度灵活的表达能力,并让创建一门新编程语言从未如此简单!当然,Lisp 有各种方言,其中甚至有没宏的 Lisp,很神秘。
Lua 的哲学是精简和快速,适合嵌入。它的定位很精准,因此一直以来被用于嵌入各种软件的脚本语言,比如游戏开发。当然,Lua 由于它缺乏一套统一的 OOP 标准(元表形式),说实话最近甚至有被 QuickJS 取代的征兆……地位大不如前了。
Transact-SQL 是啥——TIOBE 你告诉这也能算编程语言?SQL 排在上头已经够离谱了,现在还来个 TSQL,你是真的牛批。
Objective-C。这东西其实要说和 C 的关系,其实和 Smalltalk 的关系更大。很大程度上,Swift 继承了 Objc 的设计哲学,例如显式命名参数。Objc 设计得这么别扭,其目的是将 C 的语法和 Objc 的语法分离开,并用 Smalltalk 的方案实现了面向对象,既保留了 C 的指针,又有点脚本语言的感觉,很神必……
F#,函数式路线的 C#,ML 语系当前被最广泛使用的语言……设计哲学根本上是 ML 的那一套,但是又揉了 C#的东西进去,很有趣,但也失去了 ML 的一些纯粹性,所以很多人不认为 F#是正常的 ML。总体来说很有微软的那套味道,又想实用,又想保持语法的自洽和优美,但总是让人感觉稍微有点重(这就是代价),除此之外大家都觉得很好,没什么大的缺点。和 C#一样,最大的问题是它的爹是微软。
COBOL 的哲学就是自然语言编程,适应英语母语者。很明显,COBOL 在当时获得了成功,但现在显然是失败了。
Groovy——我不知道为啥在 TIOBE 上 Groovy 排名比 Scala 甚至 Kotlin 高,我怀疑这是因为 TIOBE 把 Gradle 脚本算成 Groovy 了,那确实没问题。Groovy 的哲学是创造一个零迁移成本的动态版 Java,一切 Java 代码都是合法的 Groovy 代码(理论上),而你可以随着熟悉 Groovy 语法慢慢地用上 Groovy 特有的语法。然而由于 Groovy 是个动态语言,缺少 IDE 提示,Java 社区不是很感冒。
PL/SQL 是 TIOBE 的又一次抽疯,我不认为把 SQL 放进编程语言排行里是正常的思路。
Kotlin 的哲学是创造一个稍微妥协点的 Scala,最重要的是与 Java 的互操作性,要保证与 Java 生态的无缝对接,在这方面它非常成功。Kotlin 加入了一大堆语法糖和先进的语法,让你写得爽的同时又能无缝调用 Java 库,非常成功,而且得益于有个 Jetbrains 这好爹,刚出生就带有非常完美的 IDE。
Julia 的哲学就是适应科学计算,且追求高性能。本质上是不满于 Python 而设计出来的产物。Julia 提供了对并行计算的原生支持,性能非常好,语法现代化,专门对科学计算进行特化。其中也有一些语法上的亮点,例如多重派发。严谨、简洁、科学、高性能,Julia 在我看来完美适应了“公式翻译器”这一需求。
Scala 的设计哲学是将 OOP 与 FP 统一到一起,创建一门多范式语言。别看这点现在很普通,在当时可是引起了巨大轰动。除此之外,Scala 还引入了各种语法,为了在一门静态类型语言里创建非常强大的语言系统,甚至不弱于 Ruby 的 DSL。当然,自由是有代价的——Scala 的学习成本过高,而且本身由于存在 OOP,也不够纯,导致很多 FP 程序员不够看得上 Scala。最大的问题是,Scala 虽然理论上能够与 Java 对接,但很麻烦,与 Java 库的兼容性存在很多问题,于是很遗憾地被后来出现的 Kotlin——一门可以被视作弱化版 Scala 的语言——几乎击败了。Scala 就是那种很学院派,理论上看起来啥都有,但真要用起来,发现还没有 Kotlin 爽。
Logo 的设计哲学很 Lisp——因为它实际上就是 Lisp 的一个变种。作为教学语言,Logo 有一些很独特的特性,它语法非常简单,但又像 Lisp 一样灵活。它开箱即可直接进行画图,对于孩子的探索和激发兴趣很有价值。它自身使用递归而非循环,这对于培养函数式思维很有帮助。Logo 第一次将数学直接与图形化的编程探索结合,我认为这其实是很超前的。
Dart 其实没有什么设计哲学,也没有什么特性。它的哲学硬要说就是中庸。Dart 几乎没有语言特性是自己的,几乎全是从别的语言里抄来的,这导致 Dart 真有点精神分裂的感觉。它没有一个真正的设计目标,好像只是为了设计而设计。说实话,要是没有 Flutter,Dart 绝对是起不来的。Dart 最初是要取代 JS,但要我说这么一门乏味的语言,真是让人没什么用的兴趣,要不是 Flutter 救了一手,它早就寄了。但是,对于生产来说,乏味与中庸其实不是一件坏事,也可以说它是“该有的都有了”。
RPG——天哪,这 IBM 的古董语言怎么能进 TIOBE 的前五十的,怕不是把 Role Play Game 也当作关键字算了进去吧……这东西真的太恶心了,全是槽点,完美展示了 1959 年的人们如何理解编程语言。如果说 C 成功地将汇编伪装成了高级语言,那么 RPG 就是失败地让高级语言看起来像汇编,而且更令人费解。
Haskell 的设计哲学就是优先考虑学术研究,这些年为了实用稍微做了点妥协,但不多。Haskell 很好地保持了它作为函数式语言的纯粹性,没有一点可变性,并且有(相对来说比较)高级的类型系统和推断能力。与 Idris 这种比起来在类型系统上还是稍稍有点差距,但作为一门上世纪一堆 PLT 研究者为了做研究搞出来的语言,Haskell 能有今天这样无疑是个奇迹。
Bash 的设计哲学是命令行特化。就突出一个关键字简短,熟悉了命令之后用起来方便不罗嗦,一切从简,在管道里传字符串。这点上 Powershell 就采取了完全不同的设计思路,也很难说孰优孰劣。但是 Bash 这个,确实稍微写大一点的脚本就会觉得它是一坨屎。
CFML——上古 Web 开发软件 ColdFusion 所使用的标记语言。设计哲学就是向 XML 看齐。很少有图灵完备的语言是真拿 XML 当架子的,CFML 就是其中之一。反正这个一堆尖括号我是真的难以接受……除此之外,CFML 也是存在一个 CFScript 用于替代 JavaScript 的,和 JS 只存在很少的一些区别。也就是说 ColdFusion 当年搞了一套自己的 HTML+JS。现在看来,这东西语法有点像 JSP,其实 JSP 是后辈,受了一些 CFML 的影响。总之是考古能发觉一点乐趣的古代语言,但现在就是完全没人用的古董了。
Prolog——最为人所知的逻辑式编程语言。设计哲学是比函数式更高一级的抽象,你只需要给出规则,然后问它问题,就能帮你回答出来。想法很美好,而且 Prolog 在一些特定场景,比如数值计算和规划上是真的有些好用的,比如 Prolog 可以很轻松地解决汉诺塔和八皇后问题,你只需要告诉它游戏规则就能自动解出来,完全不需要你写步骤,解数独也一样。但是 Prolog 性能不好,像上面说的八皇后问题常常要解几分钟,因为这东西本质上就是个 DFS,给你遍历可能性。Prolog 总体应用范围还是非常受限,只在特定情况下好用,其他情况下其实由于抽象程度太高,反而不好用,心智负担大。
TypeScript——我姑且认为 TS 排在这么后边是因为 TIOBE 把大部分 TS 算成了 JS。TS 的设计哲学就是给 JS 上一套类型系统,而且要尽量兼容 JS 的动态特性。由于 JS 本身太过灵活,现在导致 TS 的类型系统极其复杂,当然大多数人不会写复杂类型,遇到复杂类型就写个 any,不觉得 TS 的类型系统有多复杂。其实 TS 的类型系统真要说起来堪比 Haskell。类型体操很好玩,并且也是图灵完备的。
Scheme 的设计哲学就是一个简洁优美的 Lisp。我是不懂为啥上面出现了一个 Lisp,这里又出现了一个 Scheme。TIOBE 你要么就把方言都算 Lisp,要么就不在那儿放 Lisp,只算方言,这算啥东西啊。Scheme 是真的很优美,在语法上看起来也是一众 Lisp 里最舒服的。当然,开发起来就比 Clojure 这类差点意思,感觉还是不方便。
Powershell 作为命令行语言,采用了与 Bash 完全不同的设计思路。Powershell 是强类型、面向对象的,它甚至直接在管道里传对象。在命令行语言里,Powershell 非常先进。但有时候大家也觉得一门命令行语言不需要强类型和面向对象,因此不一定是个优点。除此之外,Powershell 继承了 C#的一贯特点,函数总是命名得很清楚也很长,比如用Remove-Item
而不是rm
。有人喜欢这种用冗长换来的清晰性,有人喜欢 Bash 的简洁。我其实更喜欢 Powershell 偏冗长的关键字,我认为清晰要优于简单与习惯性记忆。
Awk 是一门很多人都会忘记它其实是一门编程语言的语言。很多人对 awk 的了解来源于 Linux 中的 awk 命令,但其实它也是专门用来处理文本的 DSL。Awk 的哲学是文本处理特化,但它也的确是图灵完备的。很多人使用 Awk 编写一行的代码,但它实际上可以用于设计结构清晰的大型程序。我其实是很欣赏 Awk 的设计的,在本职工作上,它处理得很好。
ABAP——SAP 的专用开发语言。这东西其实设计哲学就是 ERP 特化。易学易用,简单易上手,用来对接 SAP 无比合适。这应该是少有的上古编程时代至今仍旧活跃的遗产了……主要是因为 SAP 不可能放弃 ABAP,所以估摸着再过一百年这东西还会有人在用。现在看这语言会觉得非常奇怪,很有历史气息,但由于 SAP 的存在,它是不会倒下的。
Emacs Lisp——作为一门 Lisp 方言 Elisp 有很多闪光点。它与 Emacs 高度适配,造就了 Emacs 极其强大的可扩展性,使得 Emacs 无所不能。Elisp 的设计哲学就是高度可扩展性。当然,Elisp 也有很多历史包袱,例如动态作用域问题……
ML——谢天谢地,ML 总算还在前五十里。ML 作为函数式编程的三门主要语言(Haskell/Lisp/ML)之一,有着举足轻重的历史地位。ML 是强类型、惰性求值,含类型推断的语言。同时,ML 又不像 Haskell 那么严苛,是有一些可变性的。ML 的哲学在于使用一套融入类型系统的高阶函数来构建程序,并且崇尚类型推断。ML 将一套数学的逻辑融入了编程语言中,使用高阶函数创建抽象。现代语言的很多思路,如类型推断其实都是源自 ML 的。ML 的这些优势使它语法很简洁优美,同时又不像 Lisp 一样有括号这个槽点。ML 本身很适合写编译器。
D 语言的哲学其实是要创造一个现代化的 Better C,然后又带 GC。这东西的定位是系统级语言,但又有 GC,语法也很高级,很现代化,开发效率和性能都很不错。这语言自身真没啥槽点,可能 GC 算一个槽点。D 最大的问题是社区太小且有些封闭,没找到一个合适的位置来推广自己。实际上 D 我个人认为是优于 Go 的,但 D 由于推广做得太烂,实在是没及个人用。
有点奇怪啊,还有几门应该进前五十的语言不在里面。我 Clojure 呢?我 CLisp 呢?我 Elixir,我 Erlang 呢?我 OCaml 呢?我 Smalltalk 呢?我 VBS 呢?我 Zig 呢?我 Racket 呢?我 Idris 呢?我 Elm 呢?我 ReScript 呢?要说这几个语言都进前五十是不太可能的,但都没进就怪了啊。