Files
codex-bot ef1ba88161
Verify and deploy Tabularium / verify-and-deploy (push) Waiting to run
Add language design question collection with discussion decisions and provenance
2026-10-28 14:02:12 +08:00

137 lines
7.2 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 10 · 错误与资源
0/16 项已确认。当前推进 10-01;本分类尚未完成选择。
本页整理原讨论的问题、验收要求和候选方案。勾选代表讨论中已确认的规则,不代表编译器或运行时已经实现。
## 10-01 失败的基本控制流
- [ ] 待讨论
确定使用错误结果、异常还是混合机制,以及失败后调用处如何继续。
## 10-02 错误的表示与分类
- [ ] 待讨论
确定错误携带哪些信息、如何区分类别和匹配处理器,是否允许自定义错误。依赖【对象与类型模型】。
## 10-03 失败是否属于接口契约
- [ ] 待讨论
确定函数是否声明可能的失败、调用者是否必须处理,以及遗漏处理如何检查。依赖【类型系统】。
## 10-04 向上传播与机制转换
- [ ] 待讨论
确定自动或显式传播规则,以及错误结果与异常之间是否允许转换、转换保留什么信息。
## 10-05 捕获与恢复
- [ ] 待讨论
确定处理器的匹配顺序、可见范围、重新传播,以及处理后从哪里继续;明确是否支持回到失败点继续执行。
## 10-06 退出作用域与栈展开
- [ ] 待讨论
确定错误跨越调用和作用域时的退出顺序,哪些清理必须执行,以及清理能访问哪些仍有效的数据。
## 10-07 清理结构与执行时机
- [ ] 待讨论
决定支持哪些 `finally`、`defer` 或资源作用域机制,明确注册时机、执行顺序,以及正常结束、提前返回和错误退出的行为。
## 10-08 资源责任与关闭规则
- [ ] 待讨论
确定谁负责关闭、责任能否转移,以及共享、重复关闭和关闭后使用如何处理。依赖【所有权与生命周期/类型系统】。
## 10-09 清理过程中再次失败
- [ ] 待讨论
确定原始错误与清理错误如何保留,后续清理是否继续,以及最终向外报告什么。
## 10-10 析构、终结与 GC 的边界
- [ ] 待讨论
确定是否提供析构或终结机制、执行保证及限制,明确内存回收能否承担资源关闭责任。依赖【内存管理与运行时】。
## 10-11 不可恢复失败与终止
- [ ] 待讨论
区分可处理失败、程序缺陷和强制终止;确定各类情况下是否展开和清理,以及未处理错误到达程序边界后的行为。
## 10-12 异步操作与取消中的清理
- [ ] 待讨论
明确是否支持异步清理、取消如何传播,以及清理期间再次取消的行为。依赖【并发与异步】。
## 10-13 并发中的多个失败
- [ ] 待讨论
确定任务失败由谁接收,多个失败如何组合,其他任务是否继续或取消。依赖【并发与异步】。
## 10-14 资源协议与外部接口边界
- [ ] 待讨论
明确语言内置保证与库协议的分工,以及外部调用的错误如何进入本语言、跨越外部调用时谁负责清理。依赖【定制协议、标准库与外部互操作】。
## 10-15 错误诊断与上下文保留
- [ ] 待讨论
确定是否保留调用位置、传播路径、原始原因与附加上下文,以及包装、重抛后保留什么。
## 10-16 跨分类一致性验收
- [ ] 待讨论
用正常返回、嵌套失败、清理失败、未处理失败及适用的取消场景核对全部规则,消除与其他分类决定的冲突和阻塞。
## 当前问题的方案与语言对照
以下沿用原讨论材料;建议和参考语言的做法均不自动成为本语言规则。
当前仍是 **10-01:常规操作失败时,返回失败结果,还是直接中断控制流?** 这里先讨论文件不存在、配置格式错误等情况,致命故障留到 10-11。
**相关语言怎样做**
| 语言 | 规则与小例子 | 好处、代价与启发 |
|---|---|---|
| **Python** | 广泛使用异常。例如 `int("abc")` 抛出 `ValueError`,跳过当前路径中的后续语句,寻找匹配的 `except`;中间函数不必逐层转发。也允许接口返回普通错误结果。[官方文档](https://docs.python.org/3/tutorial/errors.html) | 正常路径紧凑,便于外层集中处理;调用表达式本身通常看不出可能抛什么。启发:选择异常,就要接受并管理这种隐式退出路径。 |
| **JS** | 支持 `throw` 和 `try/catch`,可抛出任意值。例如 `throw "bad config"` 会中断当前路径,由外层捕获。[语言规范](https://tc39.es/ecma262/multipage/ecmascript-language-statements-and-declarations.html#sec-throw-statement) | 传播方便,但处理器不能天然假定拿到的是标准错误对象。启发:**采用异常**与**允许抛什么**是两个独立决定。 |
| **TS** | 运行时沿用 JS 的异常行为。静态检查可以约束错误的使用:启用 `useUnknownInCatchVariables` 时,捕获值默认为 `unknown`,访问其属性前需要缩小类型;这不等于静态列出函数可能抛出的错误。[官方文档](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-4.html#defaulting-to-the-unknown-type-in-catch-variables---useunknownincatchvariables) | 能提高处理代码的安全性,却不会自动消除隐式异常路径。启发:静态类型检查与失败控制流要分别设计。 |
| **Go** | 常规错误通常作为额外返回值,例如得到 `(文件, error)` 后检查 `err != nil`;返回错误本身不会自动退出调用者。另有 `panic/recover` 机制。[官方说明](https://go.dev/doc/effective_go#errors) | 检查与返回位置明确;逐层传播容易重复,也可能忽略错误。启发:显式错误值和另一种中断机制可以并存,但需要明确用途。 |
| **Rust** | 常规可恢复错误使用 `Result<T, E>`,区分 `Ok` 与 `Err`。例如 `File::open(path)?` 在失败时提前返回当前函数;不用 `?` 时,可检查或传递这个结果。[官方文档](https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html) | 结果结构清楚,传播简写减少重复;需要相应的类型与转换规则。启发:**显式结果并不要求每次手写完整分支**,传播语法可以另行设计。 |
这些实践提供参考,不替我们作决定;表中的好处与代价是取舍分析,不是对历史设计动机的断言。
**我们当前的三个候选方案**
沿用“配置文件不存在就使用默认配置,格式错误就停止启动”的例子:
- **A.常规失败统一返回显式结果**:调用者检查或显式传播。可以随后讨论传播简写,无须现在确定类型语法。
- **B.常规失败统一通过异常传播**:调用者捕获“文件不存在”来恢复,格式错误继续向外传播。
- **C.两者并存**:允许不同接口选择,但必须进一步确定分工,避免调用者不清楚该检查返回值还是捕获异常。
我的暂时建议是优先考虑 **A**:它让失败路径容易在调用处辨认,也能通过传播简写减少重复。如果你更重视多层调用后集中处理错误,**B** 更值得选。选择 **C** 则需要有明确的两类使用场景,收益才足以抵消复杂度。语言用途尚未确定,这个建议仍是候选。
你更倾向 **A、B,还是 C**?
## 讨论来源
《语言设计 10:错误与资源》,整理日期 2026-10-28。章节编号沿用原清单。