Files
endorphin-tabularium-docs/content/docs/language-design/04-questions.md
T
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

7.1 KiB
Raw Blame History

04 · 存储与生命周期

0/20 项已确认。当前推进 04-01;本分类尚未完成选择。

本页整理原讨论的问题、验收要求和候选方案。勾选代表讨论中已确认的规则,不代表编译器或运行时已经实现。

04-01 赋值的默认语义

  • 待讨论

明确赋值默认是独立值、共享还是移动;是否按值的类别区分,以及如何识别这种区别。

04-02 创建、身份与存储位置

  • 待讨论

明确何时产生新实例、身份是否可观察,以及存储位置和地址是否属于语言保证。依赖:对象与类型模型。

04-03 初始化流程

  • 待讨论

明确初始化顺序、必需字段、默认值和“可正常使用”的判定条件。

04-04 初始化期间的访问与逃逸

  • 待讨论

明确未完成初始化的值能否被读取、调用、共享或捕获,以及违规行为。

04-05 初始化失败

  • 待讨论

明确失败如何传播、已初始化部分如何清理,以及外部可观察状态的保证。

04-06 别名与修改权限

  • 待讨论

明确多个引用能否同时存在、谁能修改,以及修改对其他持有者是否可见。

04-07 复制规则

  • 待讨论

明确哪些值可复制、浅复制与深复制的含义、内部共享关系及复制失败行为。

04-08 移动规则

  • 待讨论

明确是否支持移动、何时发生、源值之后能做什么,以及禁止移动的情况。

04-09 跨函数与闭包传递

  • 待讨论

明确传参、返回值、闭包捕获沿用哪些生命周期规则,局部值逃逸如何处理。依赖:函数与闭包相关规则。

04-10 所有权与借用

  • 待讨论

明确是否存在所有者、借用及其期限;哪些约束由静态检查或运行时检查保证。依赖:类型系统。

04-11 引用失效与悬空访问

  • 待讨论

明确销毁、容器变化、存储迁移等情况下引用何时失效,以及失效访问的处理。

04-12 自动回收机制

  • 待讨论

明确采用作用域释放、引用计数、追踪式 GC 或混合机制,并区分语言保证与实现自由。

04-13 循环引用与弱引用

  • 待讨论

明确循环如何处理,是否提供弱引用,以及弱引用失效后的访问结果。

04-14 销毁时机与顺序

  • 待讨论

明确销毁是否及时、顺序是否保证,以及正常退出和提前退出时的行为。

04-15 清理中的异常行为

  • 待讨论

明确清理失败、重复清理、清理期间重入,以及重新发布待销毁值的处理规则。

04-16 非内存资源

  • 待讨论

明确文件、锁等资源如何及时释放,是否支持显式关闭或作用域管理,以及关闭后操作的结果。

04-17 用户自定义生命周期操作

  • 待讨论

明确哪些创建、复制、移动、清理操作允许定制,其触发时机与限制。依赖:定制协议。

04-18 分配失败与手动存储能力

  • 待讨论

明确内存不足如何表现,以及是否暴露手动分配、释放或分配器选择;不支持也须明确。

04-19 并发、异步与外部接口边界

  • 待讨论

明确跨执行单元共享或转移、任务取消、外部代码持有值时的生命周期契约;不支持的能力明确排除。依赖:相应并发及外部接口规则。

04-20 跨分类一致性验收

  • 待讨论

用创建、共享、传递、失败、退出的完整例子检查已定规则;解决与类型、对象、协议和运行时规则的冲突。

当前问题的方案与语言对照

以下沿用原讨论材料;建议和参考语言的做法均不自动成为本语言规则。

当前仍是 04-01:b = a 默认意味着什么? 重点看两个问题:修改 b 是否影响 a,赋值后还能否使用 a。

  • Python:赋值建立绑定,不复制对象。
    a = [1]; b = a; b.append(2) 后,a 也是 [1, 2]。但给 b 重新赋值不会改变 a 的绑定。共享很方便,代价是可变对象的修改会沿别名传播。对我们的启发是:必须分清“修改同一个值”和“变量改为指向另一个值”。这是 Python 的语义,不依赖 CPython 的引用计数实现。官方说明

  • JS:对象赋值保留同一对象;TS 沿用这一运行时行为。
    const a = {n: 1}; const b = a; b.n = 2 后,a.n 为 2。const 限制重新赋值,不会冻结对象;数字等原始值则没有可共享修改的内部状态。TS 的类型标注不会让赋值自动复制对象。好处是对象共享直接,代价是静态类型本身不消除别名影响。启发是:绑定是否可改、值是否可变、是否共享,需要分别规定。JS 规范、TS 文档

  • Go:复制赋给变量的值,但不递归复制它引用的数据。
    a := [1]int{1}; b := a; b[0] = 2 后,a[0] 仍为 1;换成切片 a := []int{1},同样操作后 a[0] 为 2,因为复制的切片描述信息仍引用同一底层数组。好处是支持直接的数据复制,也能方便共享;代价是必须理解类型内部是否含引用。启发是:“赋值复制值”不保证整份数据相互独立。 Go 规范

  • Rust:赋值根据类型发生复制或移动。
    let a = 1; let b = a; 后仍可读 a,因为整数实现了 Copy;let a = String::from("hi"); let b = a; 后再读取 a 会被编译器拒绝。好处是无需隐式复制字符串,也能明确资源归属;代价是使用者需要理解移动、借用和复制能力。启发是:按类型区分可行,但需要类型系统支撑;“放在栈上还是堆上”并非判断复制或移动的规则。Rust 官方教程

回到我们的待选方案:

方案 普通可变数据的 b = a
A:默认独立值 修改 b 不影响 a;需要明确独立性覆盖到哪一层。
B:默认共享 修改共享内容会影响 a;需要独立副本时显式复制。
C:默认移动 转移使用资格;之后不能继续读取原来的 a。
D:按类别区分 为普通数据、共享引用、唯一资源分别规定行为;类别必须可识别。

我的建议是先从 A 或 B 确定普通可变数据的使用体验,再在复制、移动任务中检查其他类别是否需要不同规则。这样能先明确用户可观察的行为,不必提前决定完整类型系统或回收机制。这只是推进建议,尚未替你选择。

对于普通可变记录或序列,你更希望默认 A:各自独立,还是 B:共享修改?如果你希望所有权成为语言的基础,也可以直接选 C 或 D。

讨论来源

《语言设计 04:存储与生命周期》,整理日期 2026-10-28。章节编号沿用原清单。