C++之父:贝尔实验室、负开销抽象与错误


C++之父:贝尔实验室、负开销抽象与错误

Bjarne Stroustrup 是 C++ 编程语言的创建者,也是贝尔实验室的前研究员。我们谈论了贝尔实验室的情况、编程语言设计以及他的经历中的有趣轶事。

无论您在何处获取播客,都可以查看该剧集:YouTube、Spotify、Apple 播客。

时间戳

0:50 - C++ 的起源

8:46 - 贝尔实验室是什么样的

17:24 - 丹尼斯·里奇

24:00 - 何时构建编程语言

31:59 - 引导语言

33:58 - C++ 不是面向对象的

37:32 - 讨论类型系统

46:20 - 内存安全

49:26 - 标准委员会轶事

1:09:40 - 向 C++ 添加自动垃圾收集

1:18:25 - 模板实例化已图灵完成

1:21:57 - 抽象和性能

1:28:51 - AI 编写代码

1:35:54 - 他的动机

1:39:18 - 名言

1:46:48 - 反思构建 C++

1:49:12 - 顶级 C++ 书籍推荐

1:50:59 - 给年轻时的自己的建议

附:对访谈中 AI 观点的评析

成绩单

0:50 — C++ 的起源

瑞安:

[0:50] C++ 背后的起源故事是什么?

比亚内:

[0:54] 好吧,让我们从真正的开始开始吧。我在贝尔实验室找到了一份工作,那是新泽西州的一个非常好的地方。现在不再是这样了,但当时它是世界上最好的应用数学、应用工程的地方。我环顾四周,看看那里的伟大人物;他们建造了 Unix。他们做了很多背后的理论,我意识到我必须做一些重要的事情;否则,它就不属于。

[1:30] 所以我决定构建一个分布式 Unix,因为很明显计算机正在变得越来越好,网络也越来越好,所以我们需要其中之一。如果我成功了,我们就会早十年拥有 Unix 集群或者类似的东西。但当然,我做不到。这不是一个人的工作。我意识到的第一件事是世界上没有一种语言可以满足我的需要。

[2:05] 它需要两件事:对硬件的低级访问,例如内存管理器、进程实现、进程调度程序、网络驱动程序和设备驱动程序。然后它需要高级功能来表明,这台计算机上有一个模块,那台计算机上有一个模块,这是他们正在使用的通信协议,诸如此类。有很多语言可以做到其中任何一个,但没有一种语言可以同时做到这两点。

[2:43] 低级语言的明显语言是 C,因为 Dennis Ritchie 和 Brian Kernighan 就在大厅的另一边,我说分布式 Unix 是因为我在 Unix 被发明并且仍在构建的家里。对于高级语言来说,有相当多的语言,但是它们都太慢并且无法操作硬件。但我学会了使用 Simula。我认识 Kristen Nygaard 和 Ole-Johan Dahl,他们发明了面向对象编程和 Simula。

[3:22] 所以我决定必须将这两者合并。实用的方法是从 Simula 中获取类概念并将其粘贴到 C 中,以便它可以运行得更快并可用于系统编程。同时,我使类型系统变得更加规则一些。用户定义类型和类的处理方式与内置类型相同。这基本上是 C 和 Simula 都无法做到的事情的开始,这让我们开始通用编程。

[4:03] 最终,很多年后,我不得不添加超载。我们一直都有超载的情况。你可以将两个整数相加,你可以将两个浮点数相加,你可以用加号将一个浮点数与一个整数相加。这是一个单一的名字,对吗?因此,我必须概括这一点,以便能够为内置类型和用户定义类型拥有一组独特的规则。这就是它的来源。

瑞安:

[4:36] 在我看到您所做的一场讲座中,您谈到了用 BCPL 重写模拟器。这就是分布式 Unix 的工作吗?

比亚内:

[4:46] 不,那是在那之前。我去英国剑桥攻读博士学位,在某个时候,我决定需要一个分布式系统上的软件模拟器来完成分布式系统上的博士学位工作。当然,三四年后分布式Unix的想法也是出于同样的思维方式。我所做的是在 Simula 中编写了一个非常好的模拟器。 Simula 非常擅长这一点。它的名字是错误的,因为它是一种通用编程语言,而且它的坏名字根本没有帮助它。

[5:37] 但无论如何,我编写了这个模拟器,并编写了一些示例、测试用例等。一切都运行良好。然后我尝试了第一次真正的全尺寸运行,并使用了该部门的大型机并使用了很长一段时间。嗯,博士生做不到这一点。化学家和天体物理学家永远不会接受它。于是我就被踢下了机器,很明显就是Simula。

[6:19] 我可以很好地在 Simula 中编写程序,但我无法运行它。所以我采纳了这些想法,并将它们转移到一台很少使用的实验计算机上,这就是 CAP 计算机,它具有硬件保护和功能以及很棒的硬件功能。它有点不寻常,所以天体物理学家无法使用它。他们不是计算机科学家,但我可以。唯一的问题是我无法在那里运行 Simula,因为 Simula 从未移植到那种机器上。它被用在大型机上并且是专有的,并且在 CAP 计算机的环境中一切都是错误的。

所以我基本上用 BCPL 重写了我的模拟器。 BCPL 是一种使 C 看起来像高级语言的语言,并且只有一种数据类型,即字。这是一个非常痛苦的练习,但一旦我完成了它,我的程序运行速度,我估计快了大约 50 倍。我得到了我的数据并获得了博士学位。所以那很好。但我确信我再也不会像在剑桥的大型机上尝试过那样使用不充分的工具来尝试解决问题了。

[7:13] 所以我基本上用 BCPL 重写了我的模拟器。 BCPL 是一种使 C 看起来像高级语言的语言,并且只有一种数据类型,即字。这是一个非常痛苦的练习,但一旦我完成了它,我的程序运行速度,我估计快了大约 50 倍。我得到了我的数据并获得了博士学位。所以那很好。但我确信我永远不会再尝试使用不充分的工具来解决问题,就像我在剑桥的大型机上尝试过的那样。

[8:07] 所以我列出了我理想的语言应该具备的东西,而且,好吧,C 没有所有这些,但它比任何其他存在的语言都更接近。 C++就是从那里诞生的。

瑞安:

[8:25] 是的,在那次演讲中你说了类似的话。用 BCPL 编写这个程序非常困难,调试时你的头发都掉了一半。

比亚内:

[8:35] 这几乎是完全正确的。这些年来我失去了让 C++ 继续发展的另一半。但无论如何,它奏效了。

8:46 — 贝尔实验室是什么样的

瑞安:

[8:46] 你提到了贝尔实验室,我认为人们对这个话题非常好奇,因为它是一个如此传奇的地方。当您博士毕业并考虑去哪里工作时,贝尔实验室当时被称为什么?

比亚内:

[9:04] 如果您想进行大规模、世界级的实用工程,贝尔实验室就是您的最佳选择。我认为这无疑是最好的。我们当时的计算机科学家数量可能是麻省理工学院的两倍,诸如此类。计算机科学研究中心有很多优秀的人才,其中一些来自剑桥。我在剑桥的最后一年,有一天,贝尔实验室的一位人员过来发表演讲。

[9:54] 英国和计算机实验室的传统是,一天工作后,你去酒吧和其他人聊天,看看发生了什么。他说:“好吧,当你需要工作时,请给我们打电话。”于是我就这么做了,实际上,我是用自己的机票飞到新泽西的。我后来的老板桑迪·弗雷泽(Sandy Fraser)是一位出色的网络工作人员,他告诉我我来的时机不对。他们没有任何工作。当您刚刚飞越大西洋时,这不是您想听到的。不管怎样,第二天我给一个开发小组做了一次演讲,而不是研究小组,然后他们改变了主意,把我带到了研究小组,我在那里工作了几十年。

[10:34] 当你刚刚飞越大西洋时,这不是你想听到的。不管怎样,第二天我给开发小组做了一次演讲,而不是研究小组,然后他们改变了主意,把我带到了研究小组。接下来的几十年我都在那里工作。

瑞安:

[10:53] 面试过程是怎样的?

比亚内:

[10:56] 你只是和一些人交谈。例如,我记得与丹尼斯·里奇(Dennis Ritchie)进行了一次长时间的交谈,我主要与从事网络工作的人交谈。没有这样的面试过程。他们实际上已经五年没有雇用任何新人了。所以不,他们只是凭感觉做的。

瑞安:

[11:27] 所以这有点像其他人所说的你拥有的信念和可信度。就像丹尼斯·里奇和你说话,他知道你知道你在说什么?

比亚内:

[11:38] 桑迪·弗雷泽等。他们只是和你说话,看看你知道什么和不知道什么。最后,他们去找导演说,在这种情况下,我们找到了一个好人;你能让我们拥有他吗?当然,我对此一无所知。我不在场。我当时正在加州和某人谈话,接到主管的电话,说,你愿意一周后来这里工作吗?

瑞安:

[12:10] 是什么让您坚定地选择自己乘坐飞机前往?而且连工作的承诺都没有吗?

比亚内:

[12:17] 不。好吧,那是世界上最好的地方,对吧?您还需要更多吗?如果有效的话,那就最好了。如果不起作用,那又怎样?你不可能事事都成功。

瑞安:

[12:35]今天,有更多的行业比当时有更强的拉力。会是IBM还是其他公司?那将是最好的行业。

比亚内:

[12:43] 我和 IBM 谈过;他们不如贝尔实验室计算机科学研究中心。我当时在约克镇高地,与研究人员和年轻的研究人员进行了交谈。我只是认为他们没有做正确的事情,而且没有以正确的方式做事。他们比贝尔实验室的研究人员受到更多的控制和指导。

瑞安:

[13:12] 在贝尔实验室这样的地方,项目选择是如何进行的?

比亚内:

[13:19] 我认为关于如何获得良好的研究仍然存在两种哲学。一是你有一个精心设计的项目,由管理层和高层管理人员精心挑选,并提供大量资金,也许你确实派了 20 或 30 个人来解决问题,然后你解决了它,你就得到了一些伟大的东西。另一种哲学是你雇佣你能找到的最好的人,而不是告诉他们该做什么。

[14:01] 我的工作被描述为在一年的时间内做一些有趣的事情,告诉我们你做了什么,如果我们喜欢,我们会延长。明年我们将为您提供同样的优惠。顺便说一下,您告诉我们的方式是您使用九号以上的字体在一张纸上书写。因为如果你不能简单地说出你做了什么,那么你可能还没有做一些足够有趣、非常不寻常的事情。因此,当他们构建 Unix 时,他们实际上很担心,因为它最终涉及五到七个人,而且对于个人做有趣事情的世界模型来说,它变得太大了。

[15:03] 非常不同。我想说的是,平均而言,这个相当无政府主义的组织比组织良好的组织做得更好。你从贝尔实验室听到的大部分东西都来自那里。在大楼的另一部分,他们正在做硬件工作。所以我们今天使用的纤维就是从那里产生的。许多无线技术都是从那里产生的。我们的相机等电荷耦合器件就是从那里产生的。

[15:43] 他们尝试做可视电话,但无法让它工作,因为硬件还没有成熟,但他们正在尝试这样做。手机的蜂窝系统不是来自那栋大楼,而是另一栋大楼。对于贝尔实验室来说,这是一个很棒的地方。计算机科学人员倾向于与做其他事情的人交谈。我记得当我进行模拟时,我正在帮助某人为一些网络东西构建一个模拟器。

[16:18] 许多早期的 C++ 都与网络过载时发生的事情有关,我们如何处理过载协议。在这个特殊情况下,他们做得很好。他们给我回了电话,他们遇到了一个稍微大一点的问题。他们想要模拟曼哈顿的计算机流量。即便如此,我的答案是否定的,我们没有足够的计算能力来做到这一点。

瑞安:

[17:02] 不过那时候。

比亚内:

[17:04] 现在他们可能可以了,但是当然计算机流量已经变得更多了。所以也许他们不能;我不知道。我现在没有号码。然后他们给了我号码。这就是为什么我拒绝帮助他们,因为这是不可能的。

17:24 — 丹尼斯·里奇

瑞安:

[17:24] 我在做研究时在某个地方看到你说你每周和丹尼斯·里奇一起吃一次午餐,大约有 16 年之类的。你知道,他也是一个非常传奇的名字。我很好奇,你知道,你从他那里学到的任何东西,或者他给你留下的印象,是否有任何可能影响你或 C++ 的东西。

比亚内:

[17:49] 他是一个很棒的人,我们讨论了很多事情。他从未说过任何有关 C++ 的粗鲁或负面言论。事实上,在他的哈勃论文中,他指出 C++ 是 C 的明显继承者。因此,所有这些 C 与 C++ 语言之战都是荒谬的。它们根本不应该发生,它们当然也没有发生,因为,嗯,我认识丹尼斯。我们没有打架。我仍然认识布莱恩·科尼汉。这个星期五我正在和他谈话。

[18:33]我们是好朋友。是的,语言战争是愚蠢的。例如,Dennis 帮助我为 C++ 设计了 ​​Const。它曾经被称为“只读”和“只写”,但是 C 语言的人无法处理两个单词,而且它们太长了。所以我们得到了我们得到的。但这是我记得丹尼斯提供帮助的一件具体事情。他有些担心。担心重载,因为在知道调用的含义之前必须查看函数的声明。

[19:21] 但这是一种非常合理的思维方式。碰巧它有效。今天写 see 的任何人基本上一直在使用我的作品,因为函数定义和函数声明的现代语法以及调用语义来自我的早期 C++、早期串行类工作。所以当人们开始咆哮时,他们应该记住他们实际上每天都在使用我的作品。

瑞安:

[20:04] 你写的这些几乎就像 C++ 历史的历史记录,就像三篇很长的论文。我想在某些会议上我忘记了确切的内容。那里有一件关于丹尼斯·里奇的轶事。正是关于这个概念,他向 C 标准委员会提出了胖指针的想法,它也有。它还存储其大小。你提到C委员会没有批准。

比亚内:

[20:43] 丹尼斯确实看到了,但他没有参加标准委员会。我什至听到 C 标准委员会的人说,不,Dennis 不是 C 专家。他从不参加会议。很奇怪的态度。但无论如何,我们知道缓冲区溢出和范围错误的问题。显而易见的解决方案是使用 Dennis 所说的“胖指针”,它是一个指针,其所指向的元素数量附加在该指针上。

[21:24] 但这是两个词。这可能是——不,这就是为什么它没有在早期的 C++ 中使用,因为那时它们有 48 KB 的内存。当我与丹尼斯进行讨论时,我认为我们有整整兆字节。当我开始使用 C++ 时,我们有 256 KB。我知道我们将获得一兆字节。我们正在谈论它,他称它们为“胖指针”。今天在 C++ 中,它们被称为 span。

[22:04] 这个跨度来自于我与其他人在 C++ 核心指南上的合作。我们需要类似的东西。我们无法提供所需的控制和安全程度。所以我们建立了跨度,稍后它就进入了标准。但其中一些想法非常古老。

瑞安:

[22:30] 当你把真正令人印象深刻的人放在一起时,比如世界上最伟大的人,你环顾四周,就会发现其他人有多么伟大。尽管每个人都很伟大,但仅仅其他人的伟大就会给人一种冒名顶替综合症的感觉,这种感觉不一定成立。您在贝尔实验室曾感受到或看到过这种情况吗?

比亚内:

[22:52] 当然,也许我还有一点,但当然,当我来到贝尔实验室并看到门上的名字并且我读过报纸时,他们创造了我喜欢工作的领域。是的,我想我必须提高我的水平。我必须做一些比我想象的更大、更好的事情。此外,你与他们交谈并学到东西。午餐时我学到了很多东西,他们中的很多人都在谈论他们在做什么以及为什么这样做。

[23:30] 有些地方对人们有这种影响并且人才密集。剑桥大学就是其中之一。我在那里学到了很多东西。门总是开着的。由于豪厄尔斯的缘故,我们保持大门敞开几乎成了一项政策。

24:00——何时构建编程语言

瑞安:

[24:00] 当我们谈论编程语言以及一般的语言设计时,如果我今天想构建一种编程语言,那么我需要创建哪些部分来创建一种编程语言?

比亚内:

[24:17] 嗯,这是一个相对容易回答的问题。每个人都会问这个问题,但我认为这是一个错误的问题。你需要的是一个需要解决方案的问题。很多人只是想构建一种更适合他们现在正在做的事情以及他们特别正在做的事情的语言。大多数时候,使用现有语言可以很好地完成这一任务。如果您构建一种非常专业的语言,那很好。

但如果我们谈论的是更通用的语言,那么当你想与其他人一起工作时,你正在构建的东西对他们来说并不理想。有时有人问我为什么 C++ 如此庞大和复杂。有两个原因。一是历史。由于多种原因,我无法在 80 年代构建出我想要的 C++,部分原因是技术,部分原因是计算机,还有部分原因是我了解得不够,我必须学习。

[24:55] 但如果我们谈论的是更通用的语言,那么你正在构建的东西,当你想与其他人一起工作时,这对他们来说并不理想。有时有人问我为什么 C++ 如此庞大和复杂。有两个原因。一是历史。由于多种原因,我无法在 80 年代构建出我想要的 C++,部分原因是技术,部分原因是计算机,还有部分原因是我了解得不够,我必须学习。

[25:37] 所以你做标准工程的事情,你尽你所能,然后你看看什么有效,什么无效,并尝试解决问题。然后你重复一遍。这就是 C++ 的成长过程。现在有一些遗留下来的东西妨碍了人们。您有跨度,您很少使用指针,并且您当然不应该使用指针进行资源处理。这已经在你 79 年的课程中内置了,但人们没有理解,所以需要教学。

[26:19] 但无论如何,一旦你发现你有一个需要新语言的问题,那么你就开始寻找有什么,你会得到很多帮助,很多关于分析和代码生成的书籍。大多数现代语言都使用像 LLVM 这样的框架来生成合适的代码。因此,大多数与 C++ 竞争的语言都是通过使用 C 基础设施来实现的。这非常有趣。

[27:02] 但无论如何,要关注问题,不要认为你是唯一的用户。如果您认为您是唯一的用户,那么您可以构建一种专用的编程语言,这很好。当您找到正确问题的正确解决方案时,特定于领域的语言会很棒,但首先要确定问题。就我而言,问题是我需要使用同一种语言的高级和低级设施。否则,我必须使用两种语言,并且必须让它们能够正常交流。

[27:41] 当时的高级语言倾向于使用会降低性能的接口。很多时候,它们需要垃圾收集,这对于设备驱动程序或构建垃圾收集器来说并不是很好。所以是的,找出问题并尝试解决它。

瑞安:

[28:06] 当你创建 C++ 并且发现问题后,你就开始构建 C++,并且有所有这些部分,对吗?有编译器,有链接器,在它们的实现中,有解析器和所有这些东西。当您构建最初的东西时,实现技术上最具挑战性的部分是什么?

比亚内:

[28:33] 我认为没有任何部分特别具有挑战性。正如您所指出的,更多的是由许多部分组成的。我决定后来引起麻烦的一件事是我不打算碰链接器。这只是因为我四处打听,发现贝尔实验室的人们正在使用大约 25 个不同的连接器,而且就在贝尔实验室。如果我想满足我明显的初始用途,我必须编写接口或修改 25 个链接器。

没有人希望你接触他们的链接器,因为如果你犯了错误,一切都会崩溃。所以我决定了一条规则:不要弄乱链接器。后来,人们对链接器进行了修改,使它们更适合 C++。但那是在 C 成为一个主要问题之后。另一件事是有许多不同的优化器。来自不同来源的每台计算机都有不同的优化器,而且我无法编写十几个优化器。

[29:14] 没有人希望你接触他们的链接器,因为如果你犯了错误,一切都会崩溃。所以我决定了一条规则:不要弄乱链接器。后来,人们对链接器进行了修改,使它们更适合 C++。但那是在 C 成为一个主要问题之后。另一件事是有许多不同的优化器。来自不同来源的每台计算机都有不同的优化器,而且我无法编写十几个优化器。

[29:56] 我的意思是,我要在这里写一种语言,对吗?而且我不会写。如果我想成为甲板计算机的优化专家,我就可以成为那样。我有背景,我有训练,但这不是我想做的。我想首先构建一个分布式系统,然后当我的朋友和同事开始使用 Simula 类时,我想帮助他们。他们正在做网络模拟、硬件布局、卫星定位等各种有趣的事情。

[30:39] 所以这是值得做的。我认为所有这些优化器和代码生成器实际上都有一个通用接口。它被称为 C。所以让我们使用 C 作为汇编器,效果很好。 C 在低水平上非常好,这是我选择它的部分原因。所以我们将它用于低级别。我本可以隐藏 C 并重新创建一个可能更好的界面,但我决定只使用 C 并具有 C 兼容性。

[31:21]当时,我说的是我们可以犯丹尼斯·里奇的错误,我们知道这一点,我们也可以犯我的错误,但我们还不知道,所以我们会犯丹尼斯的错误。这更易于管理和理解,而且我不必教人们如何编写 for 循环之类的东西。这就是 C 兼容性的出现,部分是作为一种实现技术,部分是为了进入文化和工具支持等。

31:59 — 引导语言

瑞安:

[31:59] 我在研究中看到 C++ 被用来编写语言工具链的某些部分,我立即想到了先有鸡还是先有蛋的问题。如何使用这种语言来构建它自己使用的东西?这是如何运作的?

比亚内:

[32:23] 这是自力更生,这并不是什么不寻常的事情。所以我从 C++ 开始。我编写了一个预处理器,它完成了 C++ 类中的一些基本操作,包括相当简单的继承和重载。然后,我为 C++ 的一个子集编写了一个简单的编译器。现在我可以在通用类中使用运算符重载和重载,因此我可以构建一个处理查找和命名等事情的作用域类。

[33:22] 然后你从那里开始工作,只需在上一个版本中编写下一个版本。你继续前进,几年后,你就得到了举世闻名的 C++。我写了一本关于它的书,并且编译器问世了。但这项技术不是我发明的。这被称为引导。我想我在本科生时就被教导说你可以做这样的事情。

33:58 — C++ 不是面向对象的

瑞安:

[33:58] 大多数人看到 C++ 并认为它是一种面向对象的语言。我多次听到你说事实并非如此,或者这不是你的直接想法。这是为什么?

比亚内:

[34:10] 是的,我从未称其为面向对象的编程语言。如果你看看 C++ 编程语言的第一版,我最接近的是说有些人称这些技术为基于对象的。事实上,它更关注的是课程;它是面向类型、面向类的。它实际上很好地支持了面向对象技术。特别是,它遵循 Simula 的定义类型、定义类和定义类层次结构的模型来处理相关类组。

[35:00] 但这绝不是全部。例如,我不需要面向对象的复数。我不想说 2 点来表达数字的某些部分。我真的想说 2 加 Z,并且我希望它最终与 Z 加 2 大致相同 - 没有点,没有箭头。在过去 300 年左右的时间里,数学发展出了一种表示法。我认为笛卡尔是第一个使用这种表示法的人,而且它非常好。

[35:54] 我不希望一切都是面向对象的。此外,我想要不需要继承、不需要运行时解析的东西,而不是使用它。因此,对于算术和复数等,我想要 Fortran 兼容性。那时我非常热衷于所谓的重用。但我认为它与许多研究人员略有不同。许多研究人员希望构建一种语言,一种允许重用的系统。

[36:38] 我想重复利用现有的东西。 Fortran 有一些很棒的软件,C 有一些很棒的系统软件,并且实际上对编译器等有帮助。还有一个 Simula 也被大量使用。所以我想重用它,并且我想确保它有效。这意味着我不能脱离硬件太远。我无法建造所有被认为理想的东西,甚至无法建造我认为理想的东西。

[37:19]这就是真实的世界;这是您正在解决的真正问题。你必须尊重你对所做事情的看法所带来的限制。

37:32 — 讨论类型系统

瑞安:

[37:32] 在您编写 C++ 时,C 已经存在,并且它的类型系统比 C++ 最终的类型系统要弱。请给出您对其背后的权衡的想法。为什么选择让 C++ 的类型系统变得更强大?

比亚内:

[37:47]因为我们需要它。类型系统中的弱点是最明显的错误来源之一,而且它当然也是无休止的测试和调试的来源之一。我讨厌调试。我更愿意做设计。你无法真正进行设计或调试。有些人声称可以,但实际上不能。因此,我想将箭头移向更多有助于调试并减少运行时错误的设计。

[38:33] 类型系统就是其中之一。事实上,你今天所得到和看到的在很大程度上要强大得多。嗯,不,它是一个比当时更强大的类型,部分原因是 C++。此外,除非有强大的类型系统,否则有些东西是无法表达的。我之前提到过超载。重载对于泛型编程至关重要。如果你想编写 T 的向量,其中 T 是参数类型,则必须重载,因为你只能对 T 进行操作,前提是所有 T 都具有满足你需要的相同接口。

[39:17] 所以你需要类型系统来解决这些问题,并且可以在编译时解决。编译器变得更复杂一些,可能更慢一些,但您不需要进行太多调试。芝加哥贝尔实验室进行了一项大规模实验,他们让一些使用 C 的小组切换到 C++,他们想知道他们的生产力是否更高或更低。有些人声称较慢的编译速度减慢了他们的速度。

[40:04] 有人简单地测量了切换到 C++ 之前和之后使用了多少编译时间,他们发现计算能力上的编译时间量大致相同。也就是说,当时 C++ 的速度慢了大约两倍。但 C++ 人员的编译频率是其两倍。这只是一个实验。因子二只是一个实验,但我想转向使用更多的编译时间分辨率。

[40:51] 仍在这样做。

瑞安:

[40:53] 我的意思是,对于每种语言来说,都存在静态类型与动态类型的二分法。 C++ 是最著名的静态类型语言之一。为什么选择静态类型语言?

比亚内:

[41:09] 因为我想解决的问题。当您在 Smalltalk 等中遇到运行时错误时,您会怎么做?你进入调试器,这很有意义。如果程序员坐在屏幕前收到错误,那没有任何意义。如果电话交换机发现运行时错误,那么您必须解决它。此外,您需要性能,并且希望小程序能够装入内存。

[41:48] 即使在今天也是如此,因为我认为 99% 的计算机都是嵌入式系统,而且它们往往受到内存限制。同样,如果你进行运行时解析,你需要有足够的信息、足够的数据来进行运行时解析。我想要适应小记忆——小意味着 120k、250k、1 MB 之类的东西。我认为它对于许多系统仍然相关。

[42:32] 你可以建造一个像这样的相机;它仍然可以有几兆字节的内存。但如果你放入大量内存,内存就会变得更大、成本更高,而且电池也会更快耗尽。所以我们不这样做。手机、相机和类似的东西仍然受到内存限制。静态类型语言,即针对内存消耗进行优化的语言,在这方面做得更好。这就是我们使用它的原因;我们现在正在使用它。

[43:10] 我怀疑麦克风里也有芯片。这个世界上有很多 C++。其中的组成是C和汇编程序。

瑞安:

[43:24] 你提到了对编译时间进行的研究

比亚内:

[43:32] 如果你更早地捕捉到东西,你编译的频率就会降低,但在这种情况下可能需要更长的时间。我可以看到一个类似的类比,如果你有静态类型语言,你会更早地捕获错误,因为编译器在你把最后的东西放在一起之前会对你大喊大叫。而在动态类型语言中,错误可能会稍后出现。

瑞安:

[43:32] 你可以更早地捕捉到东西,你可以更少地编译,但在这种情况下可能需要更长的时间。我可以看到一个类似的类比,如果你有静态类型语言,你会更早地捕获错误,因为编译器在你把最后的东西放在一起之前会对你大喊大叫。而在动态类型语言中,错误可能会稍后出现。

比亚内:

[44:00] 我不知道这方面有什么可靠的研究,但你可以看看。 JavaScript 和 Python 非常流行,它们经过运行时检查,而且运行速度慢得多。我的意思是,原始 Python 的运行速度比原始 C++ 慢 70 倍。它可行的原因是许多关键的 Python 库都是用 C 或 C++ 编写的以获得性能。因此,你可以通过实际达到我开始时的观点来获得表演。

[44:43] 你需要高级的东西,你需要可以操纵硬件的东西。他们在这里使用两种语言,但基本需求仍然相同。使用动态类型语言进行尝试会更容易,因为您不必对该语言有足够的了解;你不必了解类型系统。一般的网络开发人员或天体物理学家不是计算机科学家,也不想成为计算机科学家。

[45:20] 所以那里有优势。但问题是,类型系统在静态类型语言中发现的错误稍后会在运行时发现。随着系统的增长,性能问题开始出现。此外,编写可靠的软件变得更加困难。例如,您需要使用动态语言进行更多的单元测试,因为编译器不会为您执行此操作。如果您希望保证某些事情正常工作(例如电话交换机不得崩溃,您的汽车不得崩溃,您的飞机不得崩溃),那么您需要保证,而在非常灵活的动态类型系统中很难提供保证。

46:20 — 内存安全

瑞安:

[46:20] 我认为 C++ 臭名昭著的一件事是存在内存安全问题或脚枪。

比亚内:

[46:31] 我对此感到非常厌倦。我已经好几年没有遇到过这些问题了。有人研究了缓冲区溢出和人们使用此类东西进行黑客攻击的明显问题。几乎所有这些案例都涉及人们编写 C 风格代码或使用 C 语言。Herb Sutter 进行了一次有关实际数字的演讲,这些数字非常重要。这就是这样的问题。超过 90% 的人都不会编写现代 C++。

他们使用原始指针来传递没有元素数量的东西。没有胖指针,没有跨度。你可以在 C++ 中使用它们;你可以使用它们,你可以使用向量。我们有强化的库;每个人都有执行运行时检查的强化库。苹果有,谷歌有,微软有。只是到目前为止还不是标准的。 C26 有一个标准的硬化选项。我在个人资料上所做的工作将为您提供一种保证您不会做蠢事的方法。

[47:24] 他们使用原始指针来传递东西,而不需要元素的数量。没有胖指针,没有跨度。你可以在 C++ 中使用它们;你可以使用它们,你可以使用向量。我们有强化的库;每个人都有执行运行时检查的强化库。苹果有,谷歌有,微软有。只是到目前为止还不是标准的。 C26 有一个标准的硬化选项。我在个人资料上所做的工作将为您提供一种保证您不会做蠢事的方法。

[48:12] 所以无论如何,从根本上、理论上来说,这个问题在很多年前就已经解决了,人们只是做他们一直在做的事情,并遇到他们一直遇到的问题。这让我很难过。这是让我致力于编码指南、强制配置文件和教育的原因之一。

瑞安:

[48:40] 我的意思是,教育是解决问题的一种方法。有没有办法让编译器阻止人们做所有这些危险的事情?现在的现代 C++ 中是否默认启用该功能?

比亚内:

[48:53] 不,但应该是。我建议对于 C++29,其更简单的版本应该是 C++26。但仍然有很多人,甚至在 C++ 标准委员会中,仍然非常热衷于他们的旧代码和旧的做事方式。有人说你应该只标准化行业中常见的内容,但是当错误在行业中常见时,你应该做其他事情。

49:26 — 标准委员会轶事

瑞安:

[49:26] 标准委员会是我想谈的一个话题。这很有趣。我的意思是,该语言现在由民主国家管理。我想问你的一个问题是,如果这是一个独裁国家,你对包含哪些语言功能有完全的发言权,这会不会让你过得更困难?

比亚内:

[49:48] 首先,它从来都不是独裁统治。我从来没有完全控制过。在我看来,一旦你有了一些用户,你就有了一些责任来确保他们得到帮助并且他们的东西正常工作。你不能一直破坏语言。这就是学术语言发展的作用。他们总是在不断地改进,然后就无法维持用户群体。我实际上并没有选择设立标准委员会。

[50:23] 我选择了对社区的责任。但有一天,有两个代表 IBM 和 HP 的人进来,我不记得他们代表的第三个公司是 Sun 还是 DEC。但无论如何,当时世界上最大的计算机和软件供应商来到我位于 SH9 的办公室并说道:“好吧,Bjarne,你想帮助我们在 ISO 规则下标准化 C++ 吗?”我说:“不,我不能那样做。”

[51:10]我还在做实验。它还没有完成。所以他们说,“不,Bjarne,你不明白。我们的组织不能使用不标准化的语言。他们不能使用我们可能与之竞争的公司所拥有的语言。我们有时会这样做,好吧,我们当然相信你,但不相信你的雇主。我们有时会与他们竞争。你可能会被老板碾压。不,不,不。”

[51:49]我们需要一个标准,我们需要一个标准委员会。所以这持续了大约一个小时。他们扭动我的手臂。噢,噢,噢。最后,他们说,好吧,我将按照 ANSI 规则对 C++ 进行标准化,就像你建议的那样。计算机社区需要这个。顺便问一下,ANSI 标准化规则是什么?他们告诉我,一年后我们就开始了。但事情就是这样发生的。

[52:25] 一些非常重要的组织想要这种标准化。 C++ 正在走向标准化,而 AT&T 作为软件的主要用户,也支持标准化。我发现了,所以他们也支持。我写的文档就是基于它。实际上,我重写了后来成为 ARM 的文档,即《带注释的 C++ 标准手册》,其中提供了该语言的定义、手册,以及每个功能的一些基本原理以及可以实现或已实现的某种方式。

[53:16] 这成为标准化的基础文件。

瑞安:

[53:21] 当他们用武力武装你的时候,如果你拒绝怎么办?会发生什么?

比亚内:

[53:26] 嗯,我认为 C++ 会逐渐成为一种受到一些小社区喜爱的学术立方体语言,并且它会从计算主流中消失。有人说这句话比我更强烈。他们说C是传播的,它的用法是它有一个标准;它不属于公司所有。这是有时会阻碍那些想成为 C++ 杀手的事情之一。

[54:17] 我记得 Java 的广告,人们站起来说:“我们会在两年内杀死、绝对杀死 C++。”我认为这很粗鲁。不管怎样,我们今天的 C++ 开发人员比他们说的时候多了 10 到 12 倍,所以它不起作用。

瑞安:

[54:43] C++ 是怎么回事——不完全是说这是一场战争——但只要我们看看采用情况,显然 C++ 的采用率比 Java 多得多。但我知道 Java 得到了一家大公司的支持,该公司投入了大量的营销资金,而 C 则有点,我想你已经说过它的营销几乎为零,接近于零。

比亚内:

[55:13] 三年内使用的费用接近于零,即 5,000 美元。 Sun 在 Java 广告和营销上投入的资金比在 C++ 开发上投入的资金要多得多。直到今天,标准委员会仍然面临着一个问题。它没有资金,这意味着很难做额外的实验;部署东西很困难。其他语言社区一直在窃取 C++ 编译器和工具开发人员,因为他们很优秀。

[55:59] 但这使得很难预测我们今天能够以多快的速度实施事情。我上次查了一下,C++ 标准委员会有 527 名成员。我们努力达成共识,因为如果没有达成共识,就会出现方言。我们不希望某个功能的投票结果是 60 比 40,甚至更糟糕,52 比 48。没有百分比。我们不这样做。这是痛苦的、乏味的,但也是好的。

瑞安:

[56:45] 当你说达成共识时,100% 需要批准是没有必要的。我们不需要一致同意。我们需要绝大多数。基本上,我希望看到 90%,而我们经常做到 80%。我开始担心。

比亚内:

[56:47] 没有必要100%批准。我们不需要一致同意。我们需要绝大多数。基本上,我希望看到 90%,而我们经常做到 80%。我开始担心。

瑞安:

[57:08] 编码到规则中的下限是多少?

比亚内:

[57:10] 规则中没有下限。该规则规定,什么是共识,由 ISO 委员会的召集人决定。纯粹的数字并不能说明这一点。你能想象你有 95% 对 5% 的投票吗?但谷歌、苹果、微软等公司的C++编译器和标准库的实现者都在这5%之内。这是共识吗?我可以向您保证,没有召集者会称之为共识。

瑞安:

[58:02] 直觉上这是有道理的。我有点想知道,民主决策是否需要客观规则。如果召集人做出了错误的决定怎么办?

比亚内:

[58:13] 它发生了。但你不能只有数字规则。并不是每个人都关心整个语言。并不是每个人都明白发生了什么。您可以在第三次会议上投票。因此,您可能有一个拥有投票权的人,他有八个月的标准化经验,但不了解标准化,只知道他们从他们所参与的开发组织中了解到的内容,这可能是一个很小的组织。

[58:55] 你需要一些判断力,并且你希望召集人有这样的判断力。召集人总是询问全国代表。我的意思是,达成共识的另一种方式是,你有广泛的共识,但有十个国家的代表不同意。这不是共识。即使有外观,如果有外观,如果每个人都支持它,如果它是巨大的等等,那就没有问题。

[59:35] 但是,如果出现问题,召集人会询问国家机构负责人,他会询问实施者,这些关键人物对于将投票的变更付诸实际使用是必要的。有时,教育工作者也在做出决定之前。一旦出现分歧,并不是每个人都会平等对待。

瑞安:

[1:01:45] 我在你的一些文章中看到你说你提出过的最受负面影响的想法之一是汽车。我知道汽车最终进入了这个领域,但它受到如此负面评价的背后有什么故事呢?

比亚内:

[1:02:02] 当时,这很不寻常。人们认为它正在削弱类型系统。它还为相当通用的不完全基于语法的通用编程打开了大门。 Auto是概念的开始,它是对通用代码施加约束的能力。 Auto只是最简单的约束;它必须是一种类型而不是七种。也许我解释得不够好,而且委员会里有各种各样的背景。也许他们不了解通用类型的语言,例如 ML 和 Haskell。

[1:03:04] 所以这是一种可怕的疼痛。不管怎样,我们仍然得到了它,因为我们需要类似的东西,但这还不够。我研究了工业软件和过度使用汽车的问题。仅当您了解那里需要什么时,才应使用“自动”。它在通用代码中很好,您可以最终检查类型是否正确,自动已解析为支持您要对其执行的操作的内容。

[1:03:50] 这就是概念的形式化。但总是在最后进行检查,我注意到一群人过度使用汽车,实际上是在网络框架中。他们说他们的速度被减慢了,并不是因为错误太多,但他们必须查找被调用的函数,看看 auto 可能绑定到什么。然后他们必须发表评论来说明汽车的含义。

[1:04:31] 所以你有 auto,并且注释说必须是输入通道。现在您只需定义输入通道,然后不要说“自动”,而是说“输入通道自动”。美好的。系统就是这样。我的设计只是说 auto 是最简单的概念,你应该只设置输入通道 C++ 等于 blah blah blah。但无论如何,委员会想要一个指标来表明这种情况正在发生。

瑞安:

[1:05:10] 哦,好吧,我看到了另一个关于标准委员会有时会很激烈的轶事。你提到房间两个角落之间存在穿梭外交。我认为是 IBM 和英特尔。他们都需要不同的支持。这背后的故事是什么?

比亚内:

[1:05:30] 我实际上是在和当时的 IBM 代表 Brian McKnight 交谈。我们正在讨论当时发生的一些事情,现在仍然记得。基本上,IBM 正在做……这个架构叫什么?

瑞安:

[1:05:54] PowerPC。英特尔表现也不错。他们有不同的底层硬件模型,特别是与缓存之类的协调。代表英特尔的人实际上并不是英特尔人。无论如何,也是个好人。我在演讲中使用了他的一些幻灯片。我认识这些人,但他们完全陷入僵局。

比亚内:

[1:05:55] PowerPC 和 x86。英特尔表现不错。它们具有不同的底层硬件模型,特别是与缓存之类的协调。代表英特尔的人实际上并不是英特尔人。无论如何,也是个好人。我在演讲中使用了他的一些幻灯片。我认识这些人,但他们完全陷入僵局。

[1:06:36] 我的意思是,这些都是拥有大量代码的大型组织。基本上,有些事情是可以做的。但是 IBM 的家伙 Brian 说他们有很多软件,大部分是最低级别的,甚至是微代码,这取决于他们的工作方式。做过这件事的人很久以前就离开了公司,即使英特尔人是对的,他们也无法重写所有代码并使其正确。

[1:07:38] 好的。英特尔的人也有类似的论点和类似的观点。这更好。我们正在使用它。我正在拖着脚步;他们位于一个大房间的不同角落。所以我去找英特尔的人,代表英特尔的人,问题是什么?告诉我吧。解释一下。我下去解释一下。他是这么说的。他们说,好吧,有这个,这个,这个。我再次回去,花了几个小时真正进行穿梭外交,从房间的一个角落走到另一个角落。

[1:08:18] 我们达成了协议。那是在 C++ 中。几年后,他们都同意他们现在使用的是他们以前拥有的东西和其他人带来的东西的组合。所以实际上,结果是改进,异花授粉。

瑞安:

[1:08:45] 这很有趣。为什么一定要进行穿梭外交?为什么不只是集体对话呢?

比亚内:

[1:08:50] 因为他们已经尝试了好几天了,可能在之前的会议上也尝试过,但没有成功。所以我想我只是在翻译和提问。我的意思是,那些都是专家。我不认为自己是那个级别的专家。我做过硬件,也做过微代码,所以我不是业余爱好者,但这些人真的很棒。所以 IBM 的人现在是在 Linux 上做大部分同步工作的人。

[1:09:30] 今天我们仍在使用他的东西。他有它的 C++ 版本,因此他可以将其放入 Linux 内核的底层。

1:09:40 — 向 C++ 添加自动垃圾收集

瑞安:

[1:09:40] 当我在这些论文中阅读您的文章时,在这一部分中,您似乎在 1995 年就有了将某种形式的自动垃圾收集引入 C++ 的想法。这让我感到惊讶,因为当我想到 C++ 时,我的第一反应是,没有垃圾收集器。我们将自己管理内存。那该怎么办呢?

比亚内:

[1:10:10] 有两件事。第一,我希望实现一般资源管理的自动化,而不仅仅是垃圾管理,不仅仅是内存管理。为此,你有构造函数、析构函数和后来被称为 RAII(资源获取即初始化)的技术,这可能是我有史以来最糟糕的命名。但我当时很忙。因此,在标准委员会中,那些人坚持认为我们需要能够进行垃圾收集。

[1:10:50] 那里有垃圾收集器。哦,汉斯·伯姆也在这里。他是英特尔模型的代表者。他有一个至今仍在使用的保守垃圾收集器。我们认为我们需要一个接口,以便可以标准化您如何使用此类垃圾收集器。基本上,我正在听取用户、专家用户的意见,他们认为这是必要的。我认为对内存管理和资源管理的支持很重要。

[1:11:32] 我从一开始就这么认为。我认为垃圾收集不适合我所做的很多事情。但可以肯定的是,自动化管理是理想的选择。经过长时间的讨论,我们找到了一个人们都同意的接口,并将其放入 C++ 中。我们发现,在接下来的 10 年里,随着 RAII(一直存在的资源管理)得到越来越多的理解和使用,垃圾收集的使用量逐渐减少。

[1:12:24] 此外,仍然使用垃圾收集器的人并没有使用标准接口,因为他们已经找到了做得更好的方法。今天,仍然有一些人在做垃圾收集,但这并不是标准的一部分。

瑞安:

[1:12:43] 这是如何运作的?它有点像内存分配方法的包装器吗?

比亚内:

[1:12:48] 是的,好的。你有一个不同的 new 或 malloc 实现,或者操作一个 new 或你在最低级别使用的任何东西,然后删除也变得略有不同。

瑞安:

[1:13:11] C++ 社区中有一个关于这艘船 Vasa 的警示故事,我有点好奇为什么它如此受欢迎。

比亚内:

[1:13:21] 哦,我们在某个时候在斯德哥尔摩举行了一次会议,他们有一艘很棒的船,如果你去过斯德哥尔摩,你应该看到:瓦萨号。这是一艘1600年代的战列舰。这有一个故事,这就是我告诉人们的故事。国王正在订购一艘战舰,这艘战舰应该是周围最好、最漂亮的战舰。这将是一艘优秀的战斗战舰,用于外交访问。所以应该很漂亮。他们放下龙骨并开始建造。然后他们听说一个可能的对手正在建造有两层炮甲板的战列舰。这是一艘只有一层炮甲板的老式战列舰。如果你把一艘单炮甲板战列舰放在一艘两炮甲板战列舰旁边,高度可预测的结果是单炮甲板战列舰上有很多洞,然后就消失了。

[1:14:05] 所以它应该很漂亮。他们放下龙骨并开始建造。然后他们听说一个可能的对手正在建造带有两层炮甲板的战列舰。这是一艘只有一层炮甲板的老式战列舰。如果你把一艘单炮甲板战列舰放在一艘两炮甲板战列舰旁边,高度可预测的结果是单炮甲板战列舰上有很多洞,然后就消失了。

[1:14:42] 所以国王命令这艘船现在应该有两个炮甲板。他们已经开始建造它了。所以他们增加了另一个炮台;他们在那里加了大炮。国王也观看了。现在船更大了,他们想要更多的雕像和漂亮的东西。所以就显得有点头重脚轻了。有传言说——我从未核实过这个传言,所以这可能是错误的——船舶设计师因恐惧而自杀。

[1:15:23] 另外,我不相信这只是谣言,在它建成时,他们测试了它的稳定性。测试这样一艘船稳定性的方法是让全体船员从一侧到另一侧来回运行,产生和谐的摇摆。如果你能做到14次,那么它就能经得起波罗的海和北海的考验。有传言说——实际上,正如我所说,我认为这是事实——他们这样做了七次,然后就停下来了,因为这看起来很危险。

[1:16:08] 所以这是 1624 年,我认为这艘船已经完工了。它正在起航,这是你见过的最美妙的船。它正在斯德哥尔摩港口航行,号角鸣响,旗帜飘扬,船员家属在船上,这一切都是如此。过了半个港湾,一阵风吹来,压垮了一声吼叫,就消失了。它最终会降落在没有太多氧气的地方。所以保存得很好,他们又把它捞上来,你就可以看到它。

[1:16:56] 所以我向标准委员会讲述了这个故事,并指出他们做错了一些事情。他们在没有改进基础的情况下构建了更多功能。始终改进基础,以确保它不仅仅是您添加的一组随机功能,因为这很复杂。此外,不要损害您的测试。这真的很危险。此外,你们都注意到,当你们的高层老板说应该做某事时,高层老板并不总是知道什么是正确的。有时专业的说法是,不,我们不这样做。

[1:17:43] 我们必须放轻松。如果他们说,好吧,我们将建造一艘单炮甲板战列舰,我们不会将其称为瓦萨号,而是将其称为中立的。然后明年,你就可以拥有一艘从下到上设计成两门炮的战列舰。你不会有任何问题。但高层管理人员,意思是当时在波兰的国王,所以他甚至看不到它,说,不,必须按时交付。

[1:18:17] 因此,他们按时交付了一些无法完成任务的东西。不过还是去看看船吧。这很棒。

1:18:25 — 模板实例化已图灵完成

瑞安:

[1:18:25] 在某个时候,有人证明了 C++ 模板实例化机制是图灵完备的。那么编译器将做什么来预处理 C++ 程序实际上可以用于计算。我只是想了解这是怎么可能的。有人提到了有关在编译时计算素数的内容。这是如何运作的?

比亚内:

[1:18:57] 嗯,素数只是一个好奇心。它使用错误消息来报告结果。但是当你构建一些东西时,你可以获得图灵完备性。您需要某种形式的迭代或递归,并且需要比较。就是这样。然后就可以达到图灵完备性。至少一些理论家说,“嘿,我们不能这么做。它会永远运行。”提出第一个例子的人 Erwin Unruh 实际上认为我应该以某种方式禁止它。

[1:19:50] 我应该禁止它。我的反应是:“这看起来很有用。太棒了。”我想我是对的。此外,没有什么是永远运行的。如果你有图灵机,你就有磁带,而且磁带必须是无限的。因此,如果你想象按照图灵设计的方式建造一台真正的图灵机,那么当它出现时,你必须有一群导航员一直在构建轨道。当然,我们不这样做。关键是,在我们遇到真正的问题之前,编译器就会耗尽资源。

[1:20:30] 机器是有限的,因此除非存在错误并且错误被捕获,否则问题不会成为现实。有保证。所以,这不是问题。然而,发生的事情是人们滥用模板来进行简单的计算,例如素数或可信度。筛选或计算阶乘等。它太糟糕了,而且太贵了,而且消耗了太多的内存,以至于成为一个问题。这就是我和 Gabbitas Reyes 构建 constexpr 的原因,它基本上表示你可以在编译时计算完美的普通代码。它更简单,更符合我们的习惯,而且编译速度更快,通常会产生更快的代码。

[1:21:37] 今天你就拥有了它,如果你想保证这一切完成,你就拥有了 Constexpr。这就解决了对模板真实完整这一概念的明显误用。它将它们变成普通函数。

1:21:57 — 抽象与表现

瑞安:

[1:21:57] 一般来说,对于编程语言来说,有一种高级直觉,即距离机器越近,性能就越高。例如,我倾向于认为 C 比 C++ 更接近机器。

比亚内:

[1:22:18] 不,不是这样的,不是这样的。它不如 C++ 的编译时计算。不管怎样,我们有完全相同的机器模型,因为 C 借用了 C11 机器模型。因此,如果您用两种语言编写相同的代码,您会得到相同的结果。除了 C++ 编译器可以在编译时执行更多操作,因此 C++ 运行得比 C 更快。在大多数情况下,有更多信息。如果您为优化器提供更多信息,它可以做得更好。

瑞安:

[1:23:00] 好的。是的,因为这就是我要问你的问题。您曾在某处说过 C++ 可以比 C 性能更高,但我倾向于认为更多的抽象会让您付出一些代价。

比亚内:

[1:23:12] 已编译完毕。这就是我谈论零开销抽象的原因,人们开始为此责怪我,因为这低估了 C++ 编译器的能力。我们可以进行负开销抽象。

瑞安:

[1:23:34] 如果我真的很擅长编写汇编并且我有足够的时间来编写它怎么办?相比之下如何?

比亚内:

[1:23:42] 如果你很聪明并且你有无限的时间,你可以做得更好。总的来说,我们不再像优化器那么聪明,而且我们没有无限的时间。所以如果我们足够聪明,我们只能做一小段代码。现在的问题是,我们是否有足够的时间来运用我们的智慧?这甚至开始影响聪明的代码。去年我给Slack做了一次演讲,这是一群来自金融行业非常注重绩效的人。

[1:24:33] 我的标题是“别聪明”。事实上,书面标题是“不要(太)聪明”,但我不会发音括号。我活着出来了。我的主要观点是,C++ 足以满足 98% 以上的代码。因此,如果你想让时间变得聪明,你可以使用这些技术,我展示了现代 C++。这样,您就有时间进行所有巧妙的优化。问题是,如今聪明的优化往往依赖于机器。

[1:25:15] 也就是说,如果您获得了一台新计算机或者获得了新版本的编译器,您实际上可能会悲观您的代码。自 80 年代以来,我多次看到这种情况。有些人除了在下一代硬件上使用不同的优化之外什么也不做。我改进事物的标准技术实际上是首先扔掉聪明的东西,然后看看你是跑得更快还是更慢。

[1:25:58] 通常,你跑得更快是因为聪明的东西,至少是 20 世纪 90 年代存储风格的聪明的东西,今天仍然有很多,因为这些技术在人们的头脑中继续存在,并且一些代码仍然存在,倾向于使用指针的老鼠巢,这给编译器和优化器带来了问题。他们有时还会使用更多的分配,这并不好。您想要最小化内存访问,您想要最大化缓存性能等等。

[1:26:41] 编译器在这方面做得非常好。我见过这种想法。我和我在西班牙做流体动力学的朋友一起写了一篇关于它的论文,我们扔掉了聪明的东西——实际上是一个性能测试套件的例子。所以它不是一个玩具,通过将代码减少到之前的 80% 左右,我们只得到了 20% 的改进。有些人认为这并不重要。

[1:27:26] 我认为这是该技术合适的重要证明。仅在需要时才应用优化。 Knuth 说不要过早优化,但他也指出 2% 到 3% 是你应该优化的地方,这正是我使用的数字。首先,使用高级设施构建东西,看看它是否足够好,如果不够好,你必须计时,你不能猜测你的时间。然后你找出时间花在哪里,然后进行优化。

[1:28:10] 但很多时候,你不需要去那个阶段;够快了。

瑞安:

[1:28:15] 我明白了。因此,当你在这里说“聪明”时,它就像是为了维持性能而进行的人性化手动管理。

比亚内:

[1:28:23] 是的。

瑞安:

[1:28:24] 你的意思是,实际上如果你不这样做,你就会给编译器更多的优化空间,而且它可以做得很好。比以前好多了。在 20 世纪 90 年代巧妙且正确优化的代码如今常常受到悲观对待,因为机器架构已经发生变化,编译器也已得到改进。

比亚内:

[1:28:31] 干得好,比以前好多了。在 20 世纪 90 年代巧妙且正确优化的代码如今常常受到悲观对待,因为机器架构已经发生变化,编译器也已得到改进。

1:28:51 — 人工智能编写代码

瑞安:

[1:28:51] 当我观察当今的行业时,越来越多的代码是由机器而不是人类编写的。我觉得很多编程语言的设计都在考虑如何让它适合人类解决问题和编写代码。我很好奇您是否认为如果越来越多的代码由模型和机器编写,编程语言设计是否会改变。

比亚内:

[1:29:23] 我认为在我最感兴趣的领域,代码仍然会由人类编写,并且他们会使用抽象。我见过的人工智能在这个领域生成代码的尝试的例子并没有成功。它们会产生更多的错误、更多的安全漏洞。他们的代码臃肿,这再次让人悲观,因为你使用了更多的内存,而且很难验证。验证它所需的高级开发人员已经开始退休,因为他们不想处理每次更改代码或提示时都会更改的内容的验证。此外,我考虑的很多事情都涉及监管机构的验证。您必须能够验证您所做的更改。当你做出改变时,AI、工具都会改变,即使你在提示中做了微小的改变,很多代码也会改变,你必须再次检查。

[1:30:08] 我看到他们中的一些人开始退休,因为他们不想处理每次在代码和提示中进行更改时都会更改的内容的验证。此外,我考虑的很多事情都涉及监管机构的验证。您必须能够验证您所做的更改。当你做出改变时,AI、工具都会改变,即使你在提示中做了微小的改变,很多代码也会改变,你必须再次检查。

[1:30:47] 所有生成的代码都比人类编写的代码了解更多。当人类做出改变时,它会做出局部的改变。您可以寻找局部更改的影响。如果人工智能写了它,你实际上不知道它在哪里被改变。你必须尝试弄清楚这一点。因此,如果您正在做以前已经做过很多次的事情,例如编写标准网络应用程序,那么您所说的是正确的。

[1:31:22] 此外,人工智能也并非毫无用处。我不是这个意思。它可以用来编写文档。同样,它必须经过人工验证,但它有助于编写内容。擅长文字。至少现在,它不擅长安全关键、性能关键的代码。现在,假设世界上 70% 或 80% 的代码不符合这种模式。但我感兴趣的是那 10% 或 20% 的代码。而且,它不在那里。

[1:32:09] 我不认为 LLM 模型会带来这种情况。此外,当接受训练数据时,它必须使用旧代码进行训练。在我看来,我的工作是确保人们编写新东西并使用对旧代码进行改进的新技术。我发现基于 LLM 的代码正在模仿旧代码,并再次获得旧的性能和旧的错误。也许你可以改进这一点。我听说 Bjarne 应用程序正在编写适合我的作品的传言,但即使这样也是有问题的,因为我所说的与 20 年前不完全相同。

[1:33:06] 但无论如何,我们拭目以待。此外,甚至 Dijkstra 也在研究这种可能性,他声称将自然语言作为编程语言的想法是愚蠢的。他比我没礼貌。我认为像英语这样的语言是非常灵活的,我们说的话往往是非常模糊的。我们需要一种精确的编程语言,即工程、数学;这不是英语。

瑞安:

[1:33:48] 对于那些对性能或安全至关重要的代码,我想会有一些人使用法学硕士。根据您所说的,直觉是您会预见到更多的损坏和错误,因为它是无效的。

比亚内:

[1:34:10] 真正擅长这类事情的人往往不想花所有时间进行验证。另一个问题是他们想淘汰初级程序员,因为初级程序员数量很多。但如果这样做的话,高级程序员从哪里来呢?我们会看到的。我的意思是,十年后你可以再问我同样的问题,会有更多的知识。毫无疑问,我说的有些话是不正确的。我的猜测是我所说的一些内容在十年内将是正确的。人工智能支持者总是告诉我,问题要么已经解决,要么在下一个版本中得到解决。但我听说 Anthropic 4.7 比 4.6 存在更多问题,原因我不明白。认为下一个版本将解决问题的想法始终是一个危险的假设。而且,它变得越来越贵。

[1:34:42] 我的猜测是我所说的一些内容在 10 年后将会是正确的。人工智能支持者总是告诉我,问题要么已经解决,要么在下一个版本中得到解决。但我听说 Anthropic 4.7 比 4.6 存在更多问题,原因我不明白。认为下一个版本将解决问题的想法始终是一个危险的假设。而且,它变得越来越贵。

[1:35:23] 如果你必须建造一个耗资 1 亿美元的中心并为其使用和运行电力,那么需要多少初级开发人员才能更便宜?他们开始需要钱。这并非没有问题。我所处的子领域可能比大多数领域都存在更多问题。

1:35:54 — 他的动机

瑞安:

[1:35:54] 我在您所做的个人资料中看到的一件事是,他们问您是什么让您继续使用 C++ 或是什么激励您,您说其中之一是构建未来的乐趣。第二件事是确保 C++ 向前发展的义务。当您开始接触 C++ 时,我无法想象您知道自己正在踏上一段长达数十年的旅程。

比亚内:

[1:36:21] 所以不是几十年,但我知道这是一个更长的旅程,因为我知道我无法构建我想要的语言。我可以构建它的一个子集。原因有两个。一是,嗯,我是做到这一点的团队。其次,缺乏资源和时间。我没有足够的信息来确保我的设计是正确的。所以我们面临工程问题:构建你能构建的东西,看看哪些可行,然后改进它。

[1:36:59] 所以我知道我正在陷入类似的事情。我知道我正在构建一种能够不断发展的语言。进化意味着你在知道情况不同的情况下做出某些决定。例如,这就是 C++ 不仅仅是一种面向对象的编程语言的原因之一。因为我可以看到世界上有些东西似乎不符合这种范式。所以我知道我们会进化。

[1:37:35] 这个问题答案的另一半是应用程序。很高兴看到有趣的用途等等。我当时在喷气推进实验室,我和负责火星漫游的人进行了交谈。那是很酷的东西。我去过欧洲核子研究中心。今年夏天我要去欧洲核子研究中心看看你们是如何研究高能物理的。我对高能物理一无所知。嗯,可能超过平均水平,但距离成为一名物理学家还差得很远。

[1:38:10] 所以你可以去那里看看他们做了有趣的事情,有些事情让你感到惊讶。几年前,我和欧洲核子研究中心的一个人交谈过,他的工作就是开门和关门。这些门重达几吨,由铅制成。他们移动过去封闭一个区域以防止辐射或类似的东西。具体细节我不知道,但重点是他必须启动这扇门,这并不难。你有引擎。但随后你必须确保停止它。因为当你有几吨这么宽的东西撞到墙上时,它不会停止。通常情况下,你必须写。其代码很有趣。我学到了一些东西。我仍然四处旅行并与人们交谈,看看 C++ 被用来做什么,它可以用来做什么,以及它不能用来做什么。只是学习和学习很有趣。

[1:38:45] 你有引擎,但你必须确保停止它。因为当你有几吨这么宽的东西撞到墙上时,它不会停止。通常情况下,你必须写。其代码很有趣。我学到了一些东西。我仍然四处旅行并与人们交谈,看看 C++ 被用来做什么,它可以用来做什么,以及它不能用来做什么。只是学习很有趣。

1:39:18 — 名言

瑞安:

[1:39:18] 你引用了一些我认为很有趣的引言。如果你能提供一些背后的背景就好了。其中一句引言是:“C++ 很容易搬起石头砸自己的脚。C 则让它变得更难,但当你这样做时,它会炸掉你的整条腿。”

比亚内:

[1:39:38] 八十年代在波士顿的一次演讲中,有人问了我一个问题,我想都没想就回击了那个人,但这是一个很好的引用,而且是正确的。阿诺·彭齐亚斯获得了诺贝尔物理学奖,所以他并不是一个无名小卒。我试图向贝尔实验室的一大群经理解释 C++,他说:“如果不知道如何使用它,就不可能拥有强大的工具。”所以如果你有一把锯子,你就会看到这样的东西。

[1:40:22] 如果你有一把电锯,并且你尝试这样做,它会反弹,你必须非常幸运才不会受伤。请注意,这是大致相同的故事。这背后的原因是,如果你得到了一个电动工具,但你滥用它,你会遇到更多的问题。拥有一辆加速更快的汽车,它可以将你包裹在树上,而老式的、加速缓慢的汽车则无法做到这一点。这是拥有电动工具的基础。

瑞安:

[1:41:03] 您还有另一句话:如果只懂一种语言,没有人应该称自己为专业人士。显然,您会建议人们学习 C++,但如果他们必须了解第二或第三语言才能成为更好的工程师或程序员,您会建议什么?

比亚内:

[1:41:22] 是的,如果你听说过,如果你看过那次采访,你就会知道我是故意胡言乱语的。重要的不是你知道哪些其他语言,而是你获得了嵌入这些语言中的一组想法。所以你应该做的是学习与你的语言不同的语言。我不太清楚它们是什么语言。我想我今天说过要学习一种脚本语言,那就是 Python 或 JavaScript。

[1:42:07] 然后我猜这是 Unix shell 或类似的东西。看一下函数式语言。 ML 或 Haskell 是显而易见的解决方案。或者只是选择不同的东西。关键是你不能只拘泥于你的语言中的内容。只掌握一种语言对你不好。我的意思是,你知道所谓懂得三种语言的人是什么吗?三语。谁懂得两种语言?双语。一种语言?美国是一个非常流行的笑话,至少在美国之外是这样。编程语言也是同样的想法。但我认为,对于编程语言来说更重要,因为你正在构建东西,你应该用想法和技术拓宽你的思维。

[1:42:43] 美国是一个非常流行的笑话,至少在美国之外是这样。编程语言也是同样的想法。但我认为,对于编程语言来说更重要,因为你正在构建东西,但你不应该这样做。你应该用想法和技术拓宽你的思维。

瑞安:

[1:43:08] 另一句话是,“那些自以为无所不知的人真的会惹恼我们这些自以为无所不知的人。”我很好奇这背后的背景或你对此的想法。

比亚内:

[1:43:19] 嗯,就是这样。我的意思是,这很简单。有很多人认为它们是解决世界上几乎所有问题的简单解决方案。在这种情况下,他们会过来告诉我 C++ 可以变得多么简单。这是真的。如果你只想做一件事,通常是他们想要做的事情,你可以创建一种更简单的语言。但这就像如果我们扔掉C++的这一部分,它会更简单、更好。

[1:43:57] 通常,他们想扔掉 C++ 之类的东西,但你会惹恼数百万人,而且你实际上不会成功,因为他们会坚持使用旧的东西。所以这是一种表达我对过于简单化的人感到沮丧的方式。人们认为他们无需学习编程就可以编程。他们认为自己无需学习工程学也能成为工程师。他们认为自己可以在不知道如何管理公司或国家的情况下成为政治家。

[1:44:36] 过于简单化让我很烦恼,我可能不应该表达烦恼。我很少这样做,但在这个特殊情况下,我的挫败感表现出来了。

瑞安:

[1:44:50] 是的,我在某个地方看到过 C++ 对于某些人来说很难,编程应该是平易近人的,任何人都可以学习编程。我认为您表达了这样的观点:C++ 不一定适合所有人;它适合认真的程序员。

比亚内:

[1:45:11] 是的,我的意思是,C 编程语言第一版的第一行是,“C 的设计是为了让认真的程序员的生活更加愉快。”我拿走了第一个版本,它是专业的,因为我看到了业余爱好者,它真的非常非常好。一个认真的程序员可能正在为别人编程。如果你为自己编程,那没关系;是你,这就是你的问题。

[1:45:56] 如果你为朋友这样做,你可能会失去朋友。如果你为一百万人建造一些东西,你就会对世界造成伤害。这就是它的用途。我的意思是,Guido van Rossum 构建 Python 的明确目标是让许多人,甚至每个人都可以编程。他成功了。我将 C++ 设计为对于严肃的程序员、工程师、数学家等来说是一个非常好的工具。而我也成功了。

[1:46:38] 这不是同一个问题。还记得我们从哪里开始吗?我说问题,看问题,然后从哪些有效、哪些无效中学习。

1:46:48 — 反思构建 C++

瑞安:

[1:46:48] 回顾 C++ 和整个旅程,是否有任何部分让您认为“哦,这是一个错误”,或者您在设计中学到了什么?

比亚内:

[1:47:00] 很多很多次我学到了一些东西。我认为大多数东西都没有进入 C++。也就是说,这就是你进行实验的目的,也是你最初用途的目的。我认为我的语言的主要部分是正确的,并且我认为我可以改进每一个细节。但稳定性和兼容性至关重要。如果你做了一个微不足道的改变,就会惹恼一些人,但这并不重要。如果你做出重大改变,你会惹恼很多人,而且它不会起作用,因为,比如说,一百万人会坚持旧的方式。所以我尝试在不破坏语言的情况下发展它。我有这样的事情一次又一次发生。我解释一下。人们走过来对我说:“C++ 太复杂了。你必须简化它。”我需要这两个功能。我昨天需要它们。当你这样做时,你必须给我这两个功能。

[1:47:48] 如果你做出重大改变,你会惹恼很多人,而且它不会起作用,因为,比如说,一百万人会坚持旧的方式。所以我尝试在不破坏语言的情况下发展它。我有这样的事情一次又一次发生。我解释一下。人们走过来对我说,C++ 太复杂了。是的,你必须简化它。我需要这两个功能。我昨天需要它们。当你这样做时,你必须给我这两个功能。

[1:48:34] 是的。无论你做什么,都不要破坏我的代码。我有一百万行行不通。那是不可能的。这就是为什么我致力于制定编码指南和配置文件,这些都是强制指南。这样,您可以设计一个配置文件,确保您可以使用所需的库,并确保您不会滥用您所在领域中不必要和危险的功能。

1:49:12 — 顶级 C++ 书籍推荐

瑞安:

[1:49:12] 对于任何想学习 C++ 的人来说,您最推荐的技术书籍是什么?

比亚内:

[1:49:22] 我在教本科生时写了一本书。这是偶然的;我不是故意的。无论如何,这是《C++ 编程原理与实践》的第二版。这是一本为本科生写的厚厚的书。第三版没有那么厚,因为语言有所改进,而且我实际上可以用更少的文字更好地表达想法。

[1:49:59] 但使用最新的 C++。首先学习现代方法。不要作为初学者开始学习所有编写 C 的糟糕方法。很多课程仍然说你先学习C,这样你就学会了滥用malloc和指针。然后,您可以学习如何使用向量和字符串,而不会遇到问题。但是,是的,配置文件可以使编译器和静态分析器支持这种想法。

[1:50:40] 教育工作者也在要求类似的东西。很多人认为配置文件只是为了处理内存安全和性能。不,它必须为人们提供更好的工具来学习和完成特定类型的工作。

1:50:59 — 给年轻时的自己的建议

瑞安:

[1:50:59] 最后一个问题是,如果你能回到职业生涯的起点,给自己一些建议,你会说什么?

比亚内:

[1:51:06] 哦天哪。是的,这就是时间机器问题。我有时为我的学生设定这个。你有一台时间机器。回去给丹尼斯一些建议。一旦你做到了这一点,请向前迈进 10 年并给我一些建议。这是一个很好的练习。我通常会从中得到一些非常好的故事。一些建议。我想了很多——我试图避免 C++ 中建筑类型的双向转换。我应该为此更加努力地奋斗。

[1:51:58] 我尝试过,但被贝尔实验室的人阻止了,这些人比我更有经验。我应该在那里走得更远。此外,我应该推迟 C++ 的发布,直到我可以拥有类似模板的东西,这样我就可以做一个更好的标准库。虽然这还不够好,但它会让人们养成使用标准的习惯。每个人都在构建标准库,而 Alex Stepanov 的 STL 拯救了我们。

[1:52:41] 但这真的很幸运,因为我犯了一个错误,没有延迟,直到我可以构建一个良好的向量和类层次结构。最后,如果我知道我现在对标准委员会和臃肿官僚机构的了解——而且我们现在的小组数量比开始时的成员还要多——我会非常努力地建立某种指导小组,以便人们可以提出建议。

[1:53:27] 但我们不会与 500 人一起投票。我们会从 500 人的社区中得到建议,并且我们可能会有一个由五到六个人组成的小组,他们拥有丰富的经验,他们关心整个语言并根据建议做出决定。类似的事情。但我没有经验或知识来提出这样的建议。请注意,我没有提到工具。

[1:54:03] C++ 在工具方面存在弱点,这是因为它成长的早期,工具、计算能力和内存都有限。我给学生的时间机器练习的一个限制是尝试并确保可以遵循你的建议。如果我只是说我想要这个,那么很多事情要20年后才能完成,因此永远不会发生。

[1:54:49] 有很多语言都是为未来的计算机和未来的程序员而设计的。他们中的大多数人都死了,因为十年后他们学会了这种语言时,世界已经改变了。

瑞安:

[1:55:07] 对于第一个,我想这真的很难做到,因为贝尔实验室的人员非常资深。

比亚内:

[1:55:15] 我失败了。我尝试过,但很明显你不希望缩小转化范围。去年我什至在图书馆写了一篇关于如何摆脱它们的论文。但这是 C++ 类型系统的一个根本缺陷。它的出现是因为他们需要像 Dennis Ritchie 和 Unix 团队这样的人来处理整数和浮点。他们没有想到显式类型转换,并且认为显式类型转换太笨重了。

[1:55:59] 直到获得浮点整数大约五年后,他们才真正进行了强制转换。当然,您必须能够将浮点数转换为整数,对吧?这样您就可以随时进行隐式转换。此外,诸如将整数转换为字符之类的事情也是有问题的。但由于您正在编写基础软件,因此您不想编写复杂的东西,并且您不想进行运行时检查。

[1:56:33] 你负担不起。它在我来之前很久就已经建立了,而我处理这个问题的尝试失败了。

瑞安:

[1:56:47] 听起来这并不是没有原因的。它也许可以节省资源,或者非常有限。

比亚内:

[1:56:53] 他们没有资源来处理这个问题。他们构建了 lint(静态检查器)来处理其中的一些问题和小型机器。另一件事是,这群程序员比普通开发人员聪明得多,经验也丰富得多。今天我们有了大数定律。我认为我所看到的关于全球软件开发人员数量的最新估计是 4700 万。

[1:57:28] 当时使用 Unix,程序员的数量可能只有几十个。那些没有从好大学获得博士学位的人都是天才。获得博士学位比成为天才更容易。他们用不同的机器和不同的人提出了不同的问题。男孩,这曾经是一种痛苦,现在仍然如此。

瑞安:

[1:58:02] 太棒了。非常感谢您抽出时间,Bjarne Stroustrup。我真的很感激。

比亚内:

[1:58:05] 好的,谢谢。

附:对访谈中 AI 观点的评析

本章为编者补充,不属于访谈内容。这里讨论的是当前以大语言模型为核心的编程助手,而不是对未来所有 AI 系统下结论。

Bjarne 的担忧有明确的适用背景:他关心的是编程语言、基础设施以及安全或性能关键的软件,而不是常规网页、脚本和原型。在这个前提下,他的大部分警告是正确的;但有些说法把特定工作流中的问题泛化成了 AI 的固有缺陷,还有一些只是尚未得到数据支持的预测。

基本正确的观点

1. AI 生成的代码必须经过验证

这是整段讨论中最重要、也最可靠的结论。大语言模型生成的是统计上合理的代码,而不是经过证明的正确程序。代码能编译、单元测试能通过,也不代表它没有越权、注入、资源泄漏或并发问题。

Veracode 对 100 多个模型的安全编码测试显示,只有 55% 的样本通过安全测试。一项针对 4,442 个 Java 解答的研究也发现,功能测试通过率与代码的整体质量、安全性没有直接相关性。这些结果支持 Bjarne 的核心判断:AI 产出的代码不能因为“看起来正确”就直接进入生产环境,尤其不能绕过代码审查、静态分析、测试和安全检查。

2. 安全关键、性能关键的软件更难交给 AI

这个判断基本正确。此类软件不仅要求实现正常路径,还要满足实时性、内存上限、故障模式、可追溯性和法规认证等约束。很多约束不会完整地出现在代码或提示词中,而是散落在硬件手册、历史设计决策和组织流程里。

因此,AI 可以帮助生成测试、解释代码、寻找候选优化点或完成局部实现,但最终责任仍然属于工程团队。AI 在常规任务上表现出色,不能直接推出它在航空、医疗、汽车控制或编译器后端上同样可靠。

3. 训练数据会让模型重复旧模式和旧错误

这个担忧成立。模型从大量既有代码中学习,而公开代码同时包含过时 API、不安全示例和历史包袱。当需求描述不充分时,模型往往选择语料中最常见的写法,而不一定选择项目当前最合适的写法。

不过,这不是不可缓解的硬限制。提供当前文档、仓库规则和类型信息,再让模型调用编译器、测试与静态分析工具,可以显著缩小问题。更准确的结论是:仅凭模型参数中的既有知识生成代码,容易复现旧模式;具备最新上下文和反馈回路的智能体不必局限于旧代码。

4. 自然语言不能替代精确规约

英语或中文都允许省略条件、容忍歧义,而程序必须对每个输入给出确定行为。因此,“用一句话描述需求”不能消除类型、接口、测试、状态机和安全边界。自然语言可以成为更友好的输入界面,却不能自动变成完整规约。

Bjarne 在这里区分了“表达意图”和“定义系统行为”。前者适合自然语言,后者仍需要代码、模式、测试或形式化约束。这一判断是正确的。

5. 不能假设下一代模型会自动解决当前问题

模型能力总体在进步,但不同版本可能在速度、成本、安全限制和特定任务上发生回退。单个基准分数提高,也不能证明复杂工程中的可靠性同步提高。以尚未发布或未经系统评测的下一版本作为项目计划的前提,确实风险很高。

有道理,但表述过于绝对

1. “AI 会产生更多错误、更多安全漏洞和更臃肿的代码”

已有研究发现 AI 代码存在较高的安全和可维护性风险,所以这个方向并非空穴来风。但“更多”必须说明和谁比较、使用什么模型、任务是什么,以及有没有测试和审查。一个未经训练的开发者、一个领域专家和一个带完整反馈回路的 AI 智能体,结果不会相同。

DORA 2025 报告将 AI 描述为“放大器”:它能提升交付吞吐量,也会放大薄弱测试、紧耦合架构和缓慢反馈带来的不稳定性。因此,更准确的说法不是“AI 代码必然更差”,而是“AI 提高了代码产生速度;如果验证能力没有同步提高,缺陷和技术债也会更快积累”。

2. “人类做局部修改,AI 会改动很多地方”

这描述了让模型根据提示重新生成整段代码的工作流,但不是 AI 的必然行为。现代编程智能体可以读取版本控制差异,只修改指定文件或函数,并把变更限制在很小的补丁内。反过来,人类进行架构重构时也可能制造大范围、难以审查的改动。

真正的风险是变更是否可追踪、范围是否受约束,而不是修改者是人还是 AI。小批次提交、清晰 diff、测试覆盖和可回滚性对两者都适用。

3. “AI 不擅长安全关键、性能关键的代码”

就端到端自主开发而言,这个结论符合当前现实;如果理解为 AI 在这些领域没有价值,则过于绝对。AI 可以辅助生成属性测试、模糊测试、基准代码和形式化验证条件,也可以解释性能剖析结果。关键区别是“辅助专家”与“替代专家”:前者已经有用,后者仍缺少足够证据。

不准确或缺乏证据的观点

1. “LLM 只是在模仿旧代码”

“只是在模仿”低估了模型的组合与泛化能力。模型确实受训练分布约束,但它可以组合多个模式,生成训练集中没有逐字出现过的实现,并通过编译器和测试反馈继续修正。它不是代码数据库,也不是简单复制粘贴工具。

不过,能生成新组合不等于能可靠地创造新算法或新语言设计。Bjarne 对创新能力的怀疑可以理解,但“会模仿”与“只能模仿”是两个不同命题。

2. “人类写的修改天然更容易验证”

验证难度取决于变更规模、架构、测试和作者对系统的理解,并不由作者身份决定。人类同样会遗漏影响范围,也会提交难以审查的大型改动;AI 也可以被要求给出小补丁、测试和变更说明。正确的工程原则应是:任何无法理解和验证的改动都不应合并,无论它由谁生成。

3. 用模型基础设施总成本与初级工程师工资直接比较

“建设一个昂贵的数据中心需要多少初级开发者才划算”是有感染力的反问,但不是有效的成本模型。企业通常按调用量共享模型服务,不会为每名开发者独立建设数据中心;模型还会同时服务许多产品和用户。真正应该比较的是完成同等质量任务的边际成本、复核成本、返工成本和风险成本。

4. “70%~80% 的代码不属于关键领域”

这是用于说明讨论范围的粗略估计,访谈中没有给出统计口径或来源。什么算“安全关键”“性能关键”,也会因系统边界而变化。这个数字不应作为事实引用。

尚不能判定的预测

“代码仍将由人类编写”以及“减少初级岗位会切断高级工程师的人才管道”都值得警惕,但目前属于预测,不是已经证实的事实。

AI 对生产力的影响也强烈依赖任务。METR 在 2025 年初的随机对照研究中发现,熟悉大型开源仓库的资深开发者使用当时的 AI 工具后反而慢了 19%;METR 后续数据又观察到新一代工具可能带来加速,但研究设计受到开发者选择行为影响,无法给出同样可靠的结论。这说明“AI 一定提效”和“AI 一定拖累”都过于简单。

初级岗位也可能从“手写样板代码”转向“拆解需求、验证结果和维护系统”。人才培养方式必然变化,但是否会出现高级工程师断层,取决于企业招聘、培训和责任分配,不能仅从模型能力推出。

总结

Bjarne 对 AI 的批评在他关注的领域——复杂、长寿命、安全或性能关键的软件——大体成立。他正确指出了验证成本、训练数据中的旧模式、自然语言歧义以及盲目押注下一代模型的风险。

但文章中最需要修正的,是把某些 AI 使用方式的缺陷说成 AI 的必然属性。AI 既不是可以独立负责的工程师,也不只是复制旧代码的随机机器。更现实的结论是:AI 能显著降低生成代码的成本,却没有同步消除理解、验证和承担责任的成本。代码生成得越快,工程团队越需要小批次变更、自动化测试、静态分析、安全扫描和明确的人工责任。




Enjoy Reading This Article?

Here are some more articles you might like to read next:

  • 更多大师谈 AI 编程:播客与访谈实录
  • 五位软件大师谈 AI 编程
  • Linux之父:Linus Torvalds 谈 AI 与 Linux 内核开发
  • Redis之父:不要陷入"反 AI"的炒作
  • TypeScript 之父:TypeScript 提速 10 倍,为什么 AI 不会取代软件工程师