从 Zig 学到的经验

发布: (2026年2月12日 GMT+8 09:05)
18 分钟阅读

Source: Hacker News

Zig 的方法

Zig 语言由 Andrew Kelley 创建,对标准库的范围采取了明确的立场。标准库专注于低层、基础的实用工具:内存分配器、数据结构、字符串操作以及跨平台的操作系统抽象。特定领域的功能被明确排除在外。

社区讨论已经将这一立场具体化:

  • 内存相关的操作属于标准库。 分配器、队列、字符串以及基础数据结构几乎可以服务于所有程序。
  • 文件格式处理不属于标准库。 Tar、zip、JPEG 等格式被视为过于专业化。每一种格式都是“它自己的大项目”,更适合由专门的库来实现。
  • 高级框架不属于标准库。 例如 HTTP 客户端对于通用系统语言的标准库来说并不合适。

Zig 不仅仅是避免添加组件;它还主动移除它们。std-lib-orphanage 仓库(归档于 2025 年 11 月)包含了从标准库中迁出的代码,这些代码在 MIT 许可证下发布,供社区维护。示例包括:

  • realpath() 被移除,因为它不可移植,依赖于旧的权限模型,并且“通常调用它是一个 bug”。
  • 红黑树实现被迁移到社区所有。
  • 文件系统 API 已从 std.fs 重构为 std.Io,以更好地反映其正确的范围。

这种缩减标准库的意愿相当罕见。在大多数语言社区,新增的内容都是永久的。Zig 将标准库视为需要精心策划的集合,当某些组件无法证明其维护负担的合理性时,就会被收回。

Zig 的极简主义之所以可行,是因为语言自带一流的包管理器。第三方依赖可以轻松获取。当某些功能离开标准库时,用户并不会陷入困境——只需添加依赖即可继续工作。

关键推动因素: 没有便捷的替代方案时,小型标准库会显得惩罚性。但有了包管理器,它就成为一种美德:标准库保持专注,生态系统承担其余部分。

C++ 标准化中的经济不对称

C++ 标准化的经济结构表现出一种根本的不对称。提案作者在数年内投入有限的努力。提案被接受后,这部分成本即告结束。然而,标准必须对该新增内容永久负责

  • 每一个后续提案都必须分析与该新组件的交互。
  • 每一次核心语言演进(concepts、reflection、contracts)都必须考虑其对现有库表面的影响。
  • 相邻领域的每一次缺陷报告都可能涉及它。
  • 每个编译器厂商都必须永久实现并维护它。
  • 每个 ABI 考虑都会永久限制未来的演进。
  • 每位教育者都必须决定是否教授它。
  • 每位新 C++ 程序员都必须学习它——或者学习规避它。

标准的组合复杂度单调增长,这种复杂度税在所有未来的委员会工作中不断累积,永无止境。提案者只付一次费用,其他人则承担其余全部。

这种不对称产生了经典的经济外部性。提案者获得标准化的集中收益(声望、其设计的权威地位),而分散的、永久的维护成本则在所有未来的委员会参与者之间分摊,其中大多数人在最初决策时并没有发声。

理性的激励是积极提案并不加批判地捍卫新增内容,因为提案者几乎不承担他们所带来的长期成本。如果没有迫使提案者内部化永久成本的机制,标准库将无限增长。

C++ 标准库的警示性示例

  • std::regex:发布时慢,因 ABI 限制无法修复,专家建议在性能关键代码中永不使用。
  • std::any:没人需要的词汇类型;很少使用,牺牲了类型安全,常被引用为标准化的遗憾。
  • std::auto_ptrstd::rel_ops:从发现缺陷到移除花费了十五年以上。
  • std::codecvt 方面:已废弃,但仍在维护。
  • std::filesystem:2003 年冻结的编码假设在 Windows 上产生乱码;vcpkg “完全剥离了对 std::filesystem 的使用”。

每个在提案时都显得合理。每个现在都带来持续的成本,却几乎没有相应的收益。委员会缺乏任何正式机制来审计已标准化特性是否实现了其承诺的价值。

制度衰退

Samo Burja的 伟大创始人理论 观察到,功能性制度是例外,而非常态。制度会随时间衰退,因为创造它们的活生生的知识——对 为何 作出特定决策的理解——在不完美的传递中逐渐流失。每一代人都在使用“复印的复印”,没有了生成原则,传统无法恢复失去的东西。

这种模式直接适用于 C++ 标准库。

标准库设计中的知识问题

设计原理、所考虑并放弃的权衡,以及为何选择特定 API 形态的理解——这些知识存在于创始人的脑海中,当他们离职或去世时便会消散。

Beman Dawes 设计了 std::filesystem 并维护了十四年。2020 年他去世时,伴随其设计的活跃知识传统也随之消失。委员会现在必须从规范文本中逆向推断其意图。

向标准中添加的每个组件都会产生需要保留的另一套知识传统。更小的标准库意味着:

  • 更少的传统需要维护
  • 更少的继任危机
  • 为未来的委员会成员减少累积的复杂性,便于导航

GFT对制度激励的观察

GFT 发现非功能性机构中存在一种模式:机构整体更倾向于优化外观而非功能。在 WG21 的语境下,这表现为倾向于添加组件(可见、可衡量的进展),而不是进行维护、改进或删除已有组件的更艰巨工作。

  • 没有委员会成员会因删除 std::codecvt 而建立职业生涯。
  • 职业生涯是建立在添加提案之上的。

这种不对称的激励推动了扩展,无论扩展是否真正服务于用户。

Zig的对比方法

Zig 积极 移除 标准库组件的意愿展示了一种根本不同的制度姿态:它将收缩视为合法的进步。这需要 GFT 所称的 “活跃参与者”——拥有权威和远见,能够做出官僚流程所抵制的决策的人。

Zig 的纳入标准虽隐含但明确:

组件 仅当 提供几乎每个程序都需要的低层、基础功能时才属于标准库。

C++ 应该明确这一标准。

Source:

何时应该将库组件标准化?

只有在满足以下两点时,组件才应被标准化 仅当它同时满足

  1. 稳定性信心

    • 设计已经在多年生产使用中趋于收敛。
    • 未出现需要重大接口更改的情况。
    • 已知的缺陷已得到解决,而不是被推迟。
  2. 词汇必要性

    • 不同的独立库生态系统明确需要类型一致才能互操作。
    • 有证据表明存在协调失败,而标准化可以解决这些问题。
    • 第三方分发无法解决这些失败。

“这会很有用” 是 必要但不足 的条件。有用的库可以在标准之外繁荣发展。关键在于:为什么这种有用性需要标准化,而不是通过第三方分发来实现?

Zig 的哲学之所以奏效,是因为其包管理器让外部库成为一等公民。C++ 缺乏这种机制,导致将所有东西都放入标准的压力。答案 不是屈服于这种压力——而是要投入到生态系统中去。

库扩展的机会成本

委员会的带宽是有限且宝贵的。每花费在小众库组件上的会议时间,都是一个小时 用于:

  • 受益于所有人的核心语言改进
  • 能解决真实协同失效的词汇类型
  • 使外部库更易获取的生态系统基础设施

库扩展的机会成本体现在对 只有委员会能够完成 的工作进度的延迟上。外部库可以由任何人维护;语言演进和词汇协同则需要委员会。

C++ 中的棘轮效应

C++ 标准历来将移除视为几乎不可能的事情:

  • 弃用需要十年时间。
  • 真正的移除则需要更长的时间。

这种单向棘轮保证了 无限增长

Zig 展示了一种替代方案:当某个组件不再能够证明其存在的价值时,将其迁移。代码并不会消失;它会被移动到另一个位置,在那里可以演进而不对核心造成负担。

C++ 无法完全复制 Zig 的做法——ABI 稳定性以及数十年已部署的代码使得移除变得更加复杂。但委员会可以采纳这种 思维方式

  • 添加的内容应被视为 临时的,而非永久的。
  • 每个组件都应定期证明其继续存在的合理性。
  • 如果某个设施已知存在无法修复的缺陷,诚实地承认这一点比维持假象更能帮助用户。

循环论证

  • 标准库之所以增长,是因为生态系统缺乏良好的依赖管理。
  • 生态系统停滞不前,是因为所有重要的东西都被期望放在标准库中。

打破这个循环需要选择一个方向。Zig 选择了 生态系统投资。C++ 应该考虑同样的做法。

继续扩展的后果

  • 标准会成为一个 ABI 冻结设计 的仓库,反映出它们被标准化时所依据的时代假设。
  • 注重性能的组织会放弃 std::,转而使用内部替代方案。
  • 标准库最终会变成它本不该成为的模样:在 API 边界使用,内部尽量规避

标准提供的是 规范,而非质量

  • std::regex 已被规范化,但 速度慢
  • std::filesystem 已被规范化,却存在 编码错误

规范保证的是 接口的可移植性,而不是 实现的正确性适用性

外部库可以提供自己的保证:

  • 测试套件
  • 基准测试
  • 部署证据
  • 响应式维护

这些往往比 ISO 文档编号对用户更有意义。

教学启示

初学者从连贯的标准库中获益大于从庞大的标准库中获益。

  • 一个运行良好的小型库更容易教学。
  • 一个存在诸多陷阱的大型库需要专家级知识才能驾驭。

诸如“使用 std::regex 但不要用于性能关键场景”和“使用 std::filesystem 时需注意 Windows 上的编码”等说法并不适合初学者。

结论

Zig 编程语言表明,小而专注的标准库并不是限制,而是一种优势——只要配合能够让外部库易于获取的生态系统基础设施。

C++ 面临的是不同的结构性现实:

  • 没有统一的包管理器
  • ABI 稳定性约束
  • 数十年已部署的代码

尽管如此,采用 Zig 的临时引入、定期评估、以及对生态系统的投入的思路,仍然可以帮助遏制无限制的膨胀,使标准库保持为一个有用且易于教学的基础,而不是沉重的遗留负担。

这些约束是真实存在的。 但它们并不会改变底层的经济学。标准库的每一次新增都会产生永久性的义务。每一项义务都会消耗有限的委员会带宽。维护那些后悔加入的功能所花的每一小时,都是没有用于惠及整个 C++ 社区的工作时间。

委员会最宝贵的资源是其集体的专业知识和注意力。在接受永久性义务之前要求严格的证据的哲学,比起仅仅因为希望通过广度来弥补生态系统基础设施缺失而盲目扩展标准库的做法,更能服务于 C++ 社区。

Zig 会问:“这应该放进标准库吗,还是可以交给生态系统处理?
C++ 也应当以同样的严谨,对每一个库提案提出同样的问题。

References

  • Kelley, Andrew. Zig 编程语言导论
  • Zig 标准库孤儿院。已归档于 2025 年 11 月。
  • Ziggit:标准库是否应“内置电池”?。2024 年。
  • Burja, Samo. 伟大的创始人理论。2020 年。
  • Muller, Jonathan; Laine, Zach; Lelbach, Bryce Adelstein; Sankel, David. [P3001R0] “std::hive 及类似容器不适合作为标准库的一部分”。 2023 年 10 月。
  • Winters, Titus. [P2028R0] “什么是 ABI,WG21 应该如何处理?” 2020 年。
  • Winters, Titus. [P1863R0] “ABI——现在或永不”。 2019 年。
  • Dos Reis, Gabriel. [P0939R4] “ISO C++ 的方向”。
  • Jabot, Corentin. “给你的樱桃加一块蛋糕:C++ 标准库应该包含什么?”
  • Winters, Titus. “C++ 标准库应该加入什么”。 Abseil 博客
  • R0 (2026‑02‑06): 初稿,审视 Zig 标准库哲学及其在 WG21 中的适用性。
0 浏览
Back to Blog

相关文章

阅读更多 »