这是一篇关于编程语言错误处理的长文,主要内容总结如下:
- 目标受众与阅读时间:面向对编程语言设计感兴趣且熟悉多种语言错误表示方式的从业者,预计阅读时间 60 至 90 分钟。
- 研究现状:编程语言研究常关注复杂类型系统以排除某些错误类,但对错误处理本身关注较少,与数据库领域类似。如 Yuan 等人在分布式数据密集型系统研究中发现,几乎所有灾难性故障都是软件中错误处理不当导致。
- 优秀的错误模型写作:有从业者撰写了关于错误模型的长文,如 Joe Duffy 关于 Midori 错误模型的博客、Swift 错误模型的设计文档、TigerBeetle 的“Tiger Style”文档、Rust 的 RFC 236 以及 Joe Armstrong 的关于分布式系统错误处理的演讲。
- 本文的方法与结构:以“ holistic ”(整体)和“ geared towards ecosystems of systems PLs ”(面向系统编程语言生态系统)为 approach ,结构上分为 7 个部分及一个附录,内容涵盖错误定义、关键论点、错误模型标准、假设语言 Everr 的错误模型、现有语言的错误模型、Everr 与其他语言的比较以及总结思考等。
关键定义:
- Error:程序中的不良或非理想状态,可表示为错误代码、异常等,可能带有元数据如堆栈跟踪等。
- Error propagation:传递函数调用收到的错误并可附加元数据等。
- Error handling:检查错误值及元数据并做出决策,如记录、传播、丢弃或转换。
- Error model:编程语言中表示、创建、传播和处理错误的整体系统,包括最佳实践和常见习惯用法。
关键论点:
- 程序状态是否为错误是上下文相关的,如文件打开操作在不同情境下是否为错误不同。
- 错误是否可恢复有时也是上下文相关的,如一些在应用语言中被视为不可恢复的错误在特定情境下可能可恢复。
- 错误需要能够携带元数据,以方便理解和调试错误。
- 稳健的错误处理有时需要详细了解可能的错误情况,如数据库事务的重试处理。
- 无结构形式的错误和元数据难以可靠处理。
- 程序通常需要处理既穷尽又非穷尽的错误。
- 程序员大多对错误有不完全的了解。
错误模型的关键标准:
- 错误声明:支持穷尽性注释、案例扩展、字段扩展和案例细化。
- 错误传播:支持显式标记、结构化元数据附加、错误组合和错误消除。
- 错误处理:支持穷尽性检查、结构化元数据提取、错误投影和错误恢复。
- 错误约定:包括错误类别定义、错误定义指南、错误传播指南和错误处理指南。
- 工具支持:包括 lint 支持和编辑支持。
假设语言 Everr 的错误模型:
- 有 fail-slow(使用
Result
类型)和 fail-fast(使用panic
和catch panic
)两种错误处理模式,OS 信号通过回调处理。 - 对于基本操作,默认溢出时 panic ,断言失败触发 panic ,堆内存溢出导致程序终止,栈溢出也导致程序终止。
- 支持自定义断言语义和堆分配失败处理,通过能力机制管理相关操作。
- 有 fail-slow(使用
现有语言的错误模型:
- D:推荐使用 unchecked 异常,函数可标记
nothrow
,有Exception
和Error
类型。 - OCaml:错误传播有多种方式,包括 unchecked 异常、
option
和result
类型,标准库越来越多地使用后两者。 - Ada:支持 unchecked 异常,有预定义异常,标准库广泛使用异常,GNAT 支持多种限制异常使用的设置。
- Scala:支持 unchecked 异常和
Try
类型,流行库使用异常,FP 部分更多使用 case 类和Result
。 - Nim:支持异常处理,有
raises
注解,也有可选和结果类型。 - Pony:使用
error
表达式,可通过try
块处理,不能附加数据,常用 union 类型处理错误。 - Zig:通过定义“error sets”处理错误,不能携带有效负载,支持
catch
和try
,有非穷尽枚举。 - Odin:支持 sum 类型和 enum 类型用于错误处理,不支持异常。
- Roc:推荐使用
Result
类型处理错误,整数溢出导致程序崩溃。 - Jai:未提及特定错误处理方式。
- Hare:使用
|
声明匿名 tagged union 类型用于错误处理,支持match
和?
、!
操作。 - Common Lisp:有可恢复的条件系统用于异常处理。
- D:推荐使用 unchecked 异常,函数可标记
Everr 与其他语言的比较:
- 错误声明:多数语言缺乏原生的穷尽性检查,Rust 支持相关特性但 case 细化较复杂,Everr 支持多种关于错误声明的特性。
- 错误传播 - 显式标记:多数语言在错误传播控制上各有特点,Everr 融合了多种语言的方式并通过能力机制支持不同级别。
- 错误传播 - 原始操作:多数语言对整数溢出等操作有不同默认处理方式,Everr 类似 Swift 触发 panic 。
- 错误传播 - 内存管理:多数语言在处理堆内存分配失败上方式不同,Everr 未指定内存管理策略暂不比较。
- 错误传播 - 栈溢出:多数语言不能静态保证无栈溢出,Everr 可通过能力机制减少风险。
- 错误处理:多数语言支持相关特性,Everr 的终极条件语法更通用。
- 总结思考:提出关于程序员习惯使用 untyped 错误的问题,讨论 Unix 文件 I/O API 中忽略错误的问题,引入进化语义和迁移语义的概念,探讨编程语言设计的美学和实用性,认为语言应帮助程序员更好地处理错误,最后提到可借助特殊目的语言和工具来辅助设计。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。