C++ 正处于一个挑战时间点。在第一部分,我们讨论了 Sean Parent 在 Cpp North 2022 大会上提出的“C++ 的悲剧”。在第二部分,我们将讨论 C++ 的替代方案,这些方案是用来解决什么的,以及关于 C++ 未来替代方案的一些想法。
使用 Rust 更安全
我们已经在之前的博文中比较了 Rust 和 C++。Rust 在某种程度上是独特的,它具备编译时间安全性的手动内存管理。Rust 模型不仅有助于防止内存分段故障或泄漏,而且还使得并发更容易,因为在编译时间检查了数据竞争,这些数据竞争尝试从不同线程访问相同内存且没有视同的锁定手段。
Rust 具有显著的优势和一大群粉丝,是一种优秀的语言。但它不是实验性的!它具有 C++ 的效率且没有风险部分,但并未获得预期的普及程度。
同 C++ 的大量使用相比,业内采用 Rust 慢的原因首先可能是 C++ 的起用要早得多,存在大约 30 年的遗留代码。C++ 也依赖于 C 语法。尽管 C 语法存在诸多缺陷,但它仍是家喻户晓的。但是,如果仅仅因为 C++ 抢先起步的优势,那么客观地讲,Rust 更好(甚至定义“更好”都是一个有争议的问题。多年来,业界应认识到哪种语言在各个领域是最高效的)。我们最终会看到向 Rust 大规模迁移。
目前,许多 C++ 开发者认为,在正确使用智能指针的情况下,内存管理安全性不是 C++ 的最大问题。David Sankel 在 C++ Now 2022 列出了他希望在 C++ 中看到的 Rust 功能,重点关注模式匹配的智能枚举、反射和注入元编程、优秀工具和人机功效(更安全的内存管理并不在他所需功能的列表中,因为这一问题已经在 C++ 中得到了很好的缓解)。问题在于,将这些期望的功能移植到 C++ 中并不容易。部分原因在于 C++ 的复杂性,还有一部分原因是 C++ 的演化过程使得很难将新的编程范式引入到语言中(也许有充分的理由)。正如 David Sankel 所说,这是一场艰苦的斗争。
谈话最后,David 问到:“C++ 是否面临成为遗留语言的威胁?”——不要期盼答案,这是一个公开的讨论。
归根结底,Rust 是 C++ 真正的竞争对手,它具备有吸引力的功能和真实项目应用。它似乎也在加快发展。如果没有受到什么干扰(比如Carbon?)的话,它可能会继续流行。
用 Circle 编译器抢占先机
虽然 C++ 的演化束缚于 ISO 委员会进程,但可以选择 C++ 分支。最知名的分支是 Circle ——它是一种新的 C++ 编译器,通过添加许多新语言功能来扩展 C++;其中一些语言功能基于未通过委员会或仍在渠道中的提案。
Circle 提出了许多有趣的功能,例如:
- 用类似派森(pythonic-like)方式的语法打下标
- 反射和内省
- 模式匹配
- 成员特性——对型别特性更好的语法
它是否生产就绪?我不知道任何使用 Circle 的实际项目。但它确实为 C++ 指明了可能的道路!它能否成为驱使 C++ 新变型的生产就绪编译器?或者,C++ 的另一种变型会出现并领先?重点在于,Circle 指出了 C++ 演化的潜在路径,从这个意义上说,C++ 实际上可以吸收 Circle 的想法,并根据那些在 Circle 中证明有用和有效的创新进行演化。也许是可以视为技术规范(TS)的某些东西。也许像 C++ 采用 Ranges TS 和 Concepts TS 一样,它可以吸收 Circle 的想法。或者,如果 Circle 能更普及,它可能成为一个真正的生产环境,这会使它成为一种与 C++ 竞争的新语言。
对 Circle 能力的更好展示,请参考 C++ Now 2022 大会上 Sean Baxter 的讲话—— Circle 的幕后人物。
接下来讨论 Carbon
Carbon 在 2022 年 7 月的 CPP North 大会上被宣布为 C++ 的实验性继任者。Carbon 的开发是几年前开始的(目前主分支上的第一个合并请求是大约 2.5 年前提出的,但这个分支是从一个旧的私有仓库创建的)。该语言目前由谷歌支持,但它是作为开源构建的。
Carbon 的 GitHub 页面上解释了创建 Carbon 的动机。主要想法是构建一种可以与 C++ 轻松交错的现代语言,其具有与 C++ 的双向互操作性。也就是说,你可以从 Carbon 调用现有的 C++ 代码,反之亦然。对于拥有庞大的 C++ 代码库并且希望迁移到新的现代语言的任何组织而言,这是迁移路径的巨大优势。
很难考虑 Carbon 是否真的是 C++ 的潜在继任者。首先,正如 Carbon 本身所述,它仍然是实验性的。你可以使用它,但它本身并未对外宣称可用于生产。当然,还有另一个问题,就采用一种新语言来说,Carbon 比 C++(或者比 Rust)具备哪些优点。与 Rust 相反,Carbon 尚未包含内存安全性模型,这使得它更难与 C++ 互操作。随之而来的其他好处是,当你使用时,会产生一种未完成的感觉,遇到莫名的编译错误,并体验你所期待的且仍在开发中的功能。
值得一提的是,谷歌已经推出了一种被认为是 C++ 继任者的语言—— Go。你已经可以找到关于它的提问,包括一篇 reddit 帖子,问(嘲讽?):“Carbon 是用来替代 C++ 的,但我以为 golang 才是?”然而,业界认识到,虽然 Go 有它自身的优点(这使其获得了地位),但当性能真的很重要时,它并不是 C++ 真正的替代者。这也许可以解释谷歌为什么希望提出 C++ 的新潜在继任者,这次更接近 C++ 模型。
Carbon 语法和 Rust 的基本相似性引发了一场 reddit 讨论,即 C++ 可能通过 Carbon 迁移到 Rust:
C++→Carbon 0.1→(安全)Carbon 1.0→Rust 1.x
注意,当前 Carbon 版本仍是 0.1。上述 Carbon 1.0 版本并不存在。
我的观点是,目前 Carbon 对 Rust 的威胁比对 C++ 的威胁更大,因为考虑探索 Rust 的项目和公司可能听说过一种新语言并说“让我们拭目以待,看这场争斗如何发展”。从长远来看,这可能对 Rust 有利,因为仅仅讨论就会让人们探索 C++ 的替代方案。
为什么 D、Nim 和 Zig 没有优势?
已经有人尝试提出 C++ 的继任者,它称为 D。
并且它还不是唯一的方案。还有例如 Zig、Nim 等其他语言,它们试图解决 C 语法的原罪并且通过手动内存管理保留编译语言的基本编程范式(或者像在 D 中,采用垃圾收集器但可选择是否使用它)。它们在理论上都做得很好(参考关于与 Nim 协作的 Hacker News 博文中示例),但却在争取实际采用。
决定语言成败的是什么?
这是一个非常复杂的问题。但我认为有几个共同的成功关键因素,且不要求全部具有这些因素:
- 由强大的社区和/或行业领袖支持——这至少在概念上降低了采用新语言的风险。
- 有大型知名项目作为模型,例如 Rust 的火狐浏览器(Mozilla Firefox)。
- 展示新编程范式,与其他现有语言相比可以视作工作效率飞跃。
- 解决其他现有语言中存在的问题。
- 基础知识应易于使用,复杂部分应具有充分的存在理由并隐藏。
当谈到新语言时,Carbon 提到为什么不是 Rust,但出于某些原因忽略了D。与 Carbon 相反,D 保留了与 C 的兼容性但与 C++ 的兼容性更低,并且它解释了为什么以及如何缓解这一点,这可能是支持 Carbon 的论点,也可能不是(这是一把双刃剑)。至于在 D 中使用的垃圾收集器,确实 D 允许你选择不使用垃圾收集器,但这可能会增加你代码的复杂度(D 官方博客和 D 论坛上有两个 D 的垃圾收集器的优秀资源以及如何避免或选择不使用垃圾收集器)。
很难预见一种新语言是否被广泛采用。Carbon 的一个巨大优势是它得到了谷歌的支持。我打赌,如果它没得到谷歌支持(以及根据从 C++ 社区得到的已知数据)的话,才不会得到现在这样的关注。但这不会降低它获得成功的可能性。然而,现在围绕 Carbon 的炒作和热议似乎为时过早。
其他有趣的编译语言
如果你已经在探索像 Carbon 等新语言,以下是你可以探索的几种有趣的语言:
Val ——如上文所述,Val 旨在通过受 Swift 影响的其他功能实现正确性、安全性和效率的可变值语义。它由 Dave Abrahams 等人领导,主要用于研究语义编程范式。参考语言导览页面。
Pony ——它是一种考虑内存管理和线程安全性的角色模型语言。Pony 坚持不可变状态和隔离数据来实现线程安全性和简单代码。它还没有达到1.0版本,API和语法可能会变化。
Odin ——是一种有更好型别安全性和许多其他有趣的插件和工具的类 C 语言。数据结构只是数据,没有方法,但是可以存在子类型和多态性。
不必重温这些语言或任何其他语言,但如果你正在探索语言和新编程范式,你应该知道还有很多语言!
我们试图解决什么?
我们在前面的章节中提到了新语言试图解决的问题。但非常根本的问题是,这些问题是否是实际工作效率陷阱。Fred Brooks 在其著名论文《关于软件开发中的本质性与偶然性》中将软件开发中的困难分为本质性困难、软件性质中固有的困难以及偶然性困难。这些困难是当前软件生产中遇到的,但并不是固有的。Brooks 认为,提高软件开发工作效率没有灵丹妙药,因为软件开发的主要复杂性是本质,而新工具和方法处理偶然部分。该论文发表于 1987 年,预测未来十年:
当我们展望十年以后,我们没看到什么灵丹妙药。无论在科技还是管理技术上,都没有任何单一的发展能够使工作效率、可靠性和简单性提高甚至一个数量级。
大多数软件开发者都认为 Fred Brooks 在 1987 年提出的关于未来十年的说法在 30 多年后的今天仍然成立。
那么,自然而然的问题是,新语言是否是在解决根本问题——问题的本质还是冰山一角。这不是一个简单的问题,并且实际上非常主观。甚至有人可能会说,在某些情况下,创造新语言的强烈欲望是人类试图留下印记并与众不同的本性的一部分,即使净价值是可忽略或微不足道的。
改变我们编程方式的编程范式大转变
大多数主流语言在当今仍是极为重要的。程序员需要考虑解决问题中每一小块的所有步骤。是的,我们有努力变得更有陈述性的函数、库和技术,但它最终不过是高层次抽象和低层次细微执行细节、位数和字节之间的搭配。
Tony Van Eerd 在他的 2021 C++ Now 闪电演讲中提到了“完成”一词,并在他的 Cpp North 2022 演讲中进行了阐述。Tony 对如何更轻松的构建代码提出了非常好的建议:“在下行方向从上而下编码,在上行方向从下而上编码”。你可能需要通过那个链接上的演讲来了解他的整个想法。从上而下编码并不新鲜,实际上我们大部分时间都是这么做的。问题是,当我们不这么做,就会把事情搞砸(然后就需要找大师答疑解惑。)。但是,有了任何好的建议,程序员仍然需要考虑每个函数和类别的细节与抽象层次,不要进入过多的细节,另一方面,也不要构建太多的抽象层次。我们都知道软件工程的基本定理:“除了间接层次太多的问题外,我们可以通过引入额外的间接层次来解决任何问题”(David Wheeler)。
除了考虑间接和抽象层次外,C++ 程序员还需要处理他们是想通过数值、引用或者常量引用传递的问题(忽略指针和智能指针选项)。这太技术化了,并且在许多情况下,我们在 C++ 中牺牲安全性和正确性来换取假定的效率,最终实际上损害了性能,因为共享数据对并发的代价太高。Dave Abrahams 在他的主题发言及随后的 C++ Now 2022 的第 2 部分演讲中谈到了这一点。他还介绍了 Val 语言,这是一种研究编程语言,它尝试在基于写时拷贝的内嵌效率默认情况下探索数值语义、正确性和安全性理念。虽然 Val 语言不会取代 C++,但它提出的理念可能影响 C++ 和其他语言的未来。Val 的优秀理念是,语言告诉程序员:按值发送,我们只会在需要时拷贝。在我看来,这种将负担决策丢回给语言的理念似乎是正确的方向。
编程范式大转变需要时间,也许十年,也许二十年,也许更久。但最终会出现陈述性语言,允许将重点放在问题领域,即“什么(what)”,而不是“如何(how)”——通过适当的机制来产生满足问题领域的所需执行产物。这可能是渐进式的,但我们将会看到用更具有陈述性的方式描述越来越多的系统部分,离命令式的风格越来越远。
即使我们有了这些实际上使我们的生活更轻松的新陈述性语言,我们仍然可能由 C++ 底层。
未来尚未谱写
回到 Sean Parent 在 CPP North 上的主题演讲,在主题演讲之后,Sean 发表了他的结论:
“最后一幕还未谱写。C++ 是否会继续其当前进程,尝试通过添加更多功能、更多页面、更多库和更多复杂性来解决问题?这是一条悲剧之路。使主角成功的特性同样给他们带来了失败,因为他们看不到别的办法。另一种是救赎故事,主角意识到彻底改变才是唯一的办法。”
在关于 Carbon 作为 C++ 继任者的 reddit 讨论中,其中一条回复提到:
“没有取代,只有替代方案。任何这样给你讲的人都是在提供虚假信息。”
我同意上述意见。我们现在考虑替代方案仍然为时尚早。这可能导致新语言越来越受欢迎而其他语言因此下台,但我们仍没有看到任何明显的赢家。同时,C++ 在新项目以及未来几十年需要维护的大量代码库中仍然是非常流行和大量使用的语言。是的,C++ 有它自身的挑战,但举证责任落在提出的替代方案上,而且门槛很高。
我们在上文提到了 David Wheeler 和软件工程的基本定理。Wheeler 还有一句名言:“兼容性就是可以复制别人的错误”。想想看,这很聪明。但有点肤浅。我们都知道,降低兼容性就是忽视在许多情况下不切实际的过去。新颖性与承担旧设计决策产生的技术负债的兼容性之间的紧张关系将永远存在。
我的预测是,在改变我们编程方式的编程范式大转变之前,至少还有一代新领先系统语言的空间。一种有意义地改进程序员工作效率并且可能取代 C++ 的语言。它会是可能发展加快的 Rust 吗?会是生产就绪的 Carbon 吗?或者像 Circle 这样的 C++ 分支?也许是 D、Zig 或 Nim 这样的其他竞争者?或者本文没提到的其他语言?
如果我现在必须选择,我会选 C++,但我会睁大双眼关注。
其他资源
Ginger Bill 讨论 Carbon 的一系列优秀视频:
谷歌的新编程语言“Carbon”能比 Rust 更好地取代 C++ 吗? – Slashdot
关于 Nim 与 D 对比的论坛讨论(NimLang 网站,所以可能有点主观)。
为什么现代替代语言绝不会取代 C/C++ | Shalitha Suranga | 2022 年 8 月 | Level Up Coding – 需要批判性阅读,另见本文注释。
谷歌的 Carbon 语言可能取代 C++ – levelup.gitconnected
不要被谷歌 Carbon 烧着| Erik Engheim | 2022 年 8 月 – Medium
谷歌推出 Carbon,C++ 的实验性替代 – The New Stack
谷歌为什么发布 Carbon,如何围绕谷歌思考 | Pen Magnet | 2022 年 8 月 | Better Programming