30 秒看懂
Zig 贡献者兼作者 Garrison Hinson-Hasty 与 Trevor Berrange Sanchez 讨论他的系统编程书籍。他们探讨语言设计理念,以及处理内存、陌生 API 和 C 互操作的实践方式。
- 1为变化中的语言写书Garrison 随尚未到 1.0 的 Zig 演进而更新书籍。
- 2相对于机器的简单性CHIP-8 展示了贴近机器的数据与操作。
- 3把字符串视为字节和切片Zig 提供通用工具,将编码选择留给应用。
- 4按程序阶段思考内存分配器有助于按整个阶段而非逐个节点思考内存。
- 5理解陌生 API图形编程训练程序员理解 API 的假设。
- 6从 Zig 调用 CC 头文件、defer 和可选封装使互操作更方便。
要点建议
- Garrison 随尚未到 1.0 的 Zig 演进而更新书籍。
- CHIP-8 展示了贴近机器的数据与操作。
- Zig 提供通用工具,将编码选择留给应用。
- 分配器有助于按整个阶段而非逐个节点思考内存。
- 图形编程训练程序员理解 API 的假设。
- C 头文件、defer 和可选封装使互操作更方便。
按章节阅读整理后的全文
为变化中的语言写书
Garrison 介绍背景,并说明保持 Zig 书籍内容更新的挑战。
Trevor Berrange Sanchez 介绍自己是 Zig 社区的一员。Garrison Hinson-Hasty 说,他为编译器做过贡献、帮助过社区成员,大约从 2021 年开始使用 Zig。此前他对 C、内存分配和面向数据编程的兴趣引导他接触了 Zig。
Trevor 问,为什么 Garrison 要为一门尚未到 1.0、变化频繁的语言写系统编程指南。Garrison 说这确实有挑战:访谈时他正在为 Zig 0.16 更新最后七章,并尽量选择经得起时间考验的项目和概念。
Garrison 认为,缓慢走向 1.0 是有意为之。在语言演进过程中使用它,有助于理解其设计决定;虽然这让书的维护工作增加,他仍喜欢引导读者登上这列行进中的列车。
被问到 Zig 的吸引力时,Garrison 说它的态度有些反主流。他认为许多现代软件不断在复杂性上叠加抽象;他承认框架有其存在的理由,但自己更喜欢为质量和长期使用而设计的软件。
Zig 与简单性
两人讨论经检验的思想,以及相对于机器而言简单代码的含义。
Garrison 说,Zig 运用经过检验的想法前进,而不是仅仅因为想法古老就认为它有价值。可靠性、性能和服务用户都是行业几十年来积累的经验。Trevor 也看到社区中的一部分人倾向于削减额外开销和复杂性。
Trevor 提到书中的 CHIP-8 解释器:它从整数、缓冲区和简单操作出发,而不是从复杂的管理器出发,最终将这些部件组合成解释器。他问 Zig 为何善于表达这种简单性。
Garrison 说,“简单”对不同程序员有不同含义。他对 Zig 社区这一用法的理解是:代码相对于计算机实际执行的操作是简单的;整数和指针类型能够较直接地映射到底层机器的数据表示。
Garrison 解释,CHIP-8 本身提供了一个小型计算模型。它没有现代处理器的许多复杂机制,但其内存、指令和子程序仍提供了一种思考现代计算机相关概念的方式。
他希望读者会追问字符串的内存从哪里来、到哪里去、生命周期有多长。在他看来,Zig 吸收了 C 和后续系统语言中的有用思想,同时尽量避免增加不必要的层次。
两人比较了 C 的预处理器与 Zig 的编译期功能。Trevor 指出,C 预处理器在编译之前运行,而编译期计算融入 Zig 语言本身。Garrison 认为这体现了把语言特性作为整体重新思考。
字符串与编码
Garrison 比较 Zig 的字节和切片工具与更丰富的字符串抽象。
Trevor 问起 Zig 没有内置字符串抽象的做法。Garrison 从 C 把字符串视为字节序列的方式谈起,并将其与 Zig 常用的指针加长度方式比较。这引出了编码、内存以及标准库应承诺支持什么的问题。
Garrison 回顾了部分历史背景:C 诞生时 ASCII 很常见,而 UTF-8 的设计考虑了与大量既有 ASCII 软件的兼容。如今 UTF-8 已很普遍,但某些环境仍需要处理其他编码。
其他语言提供了围绕码点和字符串的抽象。Garrison 喜欢 Zig 提供通用切片处理工具、让应用按需使用 UTF-8、码点或其他表示的决定,而不是强制采用一个包罗万象的字符串抽象。
他将这种做法与 Rust 为不同编码和内存情境提供更丰富的字符串类型相比较。他承认这些类型处理了真实的复杂问题,但认为维护整套抽象接口是一项持续负担。这是他的设计偏好,并不意味着一种方式适合所有应用。
分配器与面向数据
讨论从单个对象转向按阶段管理内存。
Trevor 转向分配器:它们在 Zig 的标准库惯例中是显式的,而书中使用的动态分配很少。Garrison 说,这主要是以扁平、面向数据的方式表示数据所产生的结果,并非单独追求的一条规则。
Garrison 指出,刚接触手动内存管理的人可能照搬高级语言中逐对象处理的模式,为每个对象单独分配内存。他描述了一种思维转变:从考虑单个请求或对象,转向考虑一批请求和数据。
在他看来,分配器最大的好处是能够按程序阶段考虑内存,而不是逐个跟踪对象。例如,可以把编译器解析阶段作为一个整体考虑,不必始终关注每个语法树节点各自的生命周期。
图形与陌生 API
OpenGL 展示了理解系统假设的通用能力。
Trevor 提到图形章节“Shader Heck”。这一章包含大量关于图形和外部 API 的内容,并不只讲 Zig 语法。他问为什么这些内容适合出现在系统编程书中。
Garrison 说,OpenGL 的历史和设计可能令人困惑,因此程序员即使完成基本任务,也需要阅读文档和外部资料。随着时间推移,他们会理解这个 API 如何看待世界,以及它期望使用者做什么。
这种能力可以迁移到其他系统:陌生硬件、软件和定制接口都有自己的假设,而且可能没有现成教程。他将委员会设计的 API 与某个人为了让任务更易理解而构建的库作了比较。
Garrison 说,他最喜欢的并不是 OpenGL 本身,而是展示如何分析舒适区之外的陌生领域。Trevor 表示赞同:关键问题往往就是,这个 API 要求我做什么?
与 C 互操作
两人讨论头文件、清理和封装。
谈到互操作时,Trevor 问 Zig 在与 C 配合方面做得特别好的是什么。Garrison 说,许多情况下从 Zig 调用 C 所需的额外工作相对较少,但程序员仍需考虑与 C 兼容的类型和约定。
Zig 可以使用 C 头文件,同时让代码继续使用 defer 等功能进行清理。对于错误返回方式或输出参数不便的 C 函数,Garrison 有时会写一个小型 Zig 封装,让周围代码使用 Zig 的错误处理。
Garrison 强调封装是可选的,并认为与 C 互操作是 Zig 的一等功能。Trevor 赞同,表示 defer 改变了他使用 C API 的思考方式。两人最后推荐了 Garrison 的书。
同频道的其他文章
39:12EN → 简体中文
22:33EN → 简体中文
34:11EN → 简体中文
28:15EN → 简体中文
46:36EN → 简体中文
28:23EN → 简体中文