Files
endorphin-tabularium-docs/content/docs/language-design/14-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

8.0 KiB

14 · 反射与表示

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

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

14-01 运行时反射的基本承诺

  • 待讨论

确定普通程序默认可以观察哪些信息,哪些需要显式声明,以及元数据是否可以被裁剪。

14-02 类型查询与类型描述的身份

  • 待讨论

确定能查询什么、返回什么,如何比较查询结果;明确静态类型、运行时实际类型与抽象接口之间的关系。依赖【类型系统】【对象与类型模型】。

14-03 元数据的内容与可用性

  • 待讨论

确定字段名、参数、注解、文档、源码位置等分别是否可查询,以及信息缺失、不同构建配置下的行为。

14-04 动态读取成员

  • 待讨论

确定按名称查找的对象范围、查找规则,以及成员不存在、不可访问、读取触发计算时的行为。依赖【对象与类型模型】【定制协议】。

14-05 动态修改成员

  • 待讨论

确定是否允许新增、写入、删除成员,以及只读值、类型不匹配和修改失败的行为。依赖【类型系统】【对象与类型模型】。

14-06 动态调用

  • 待讨论

确定是否支持通过反射调用函数或成员,以及参数匹配、默认参数和调用失败的规则。依赖【函数与调用】。

14-07 反射权限与封装

  • 待讨论

确定查看描述、读取、修改、调用分别需要什么权限,以及跨模块和私有成员的边界。依赖【模块与封装】【安全模型,如有】。

14-08 调试表示

  • 待讨论

确定默认调试文本、定制方式、信息隐藏要求,以及是否要求稳定、唯一或可重新解析。

14-09 用户字符串与格式化

  • 待讨论

确定用户文本与调试表示的关系、默认回退、格式参数和转换失败行为。依赖【定制协议】【格式化语法】。

14-10 表示过程的执行边界

  • 待讨论

确定生成文本能否执行用户代码、产生副作用或抛错,以及循环、递归深度、长度和并发修改的处理。

14-11 可序列化的值与定制入口

  • 待讨论

确定哪些值可以保存,如何处理函数、类型描述、外部资源及不支持的值;明确是否依赖反射。依赖【值与资源模型】【定制协议】。

14-12 数据格式、模式与版本兼容

  • 待讨论

确定语言承诺与格式库的分工,以及名称、缺失字段、未知字段和版本变化的处理。

14-13 反序列化与有效状态恢复

  • 待讨论

确定如何选择目标类型、是否调用构造或校验逻辑,以及无效数据、部分恢复失败的行为。依赖【类型系统】【构造与不变量】【资源管理】。

14-14 身份、共享引用与循环的保存

  • 待讨论

确定保存树还是对象图、何时保留共享关系,以及循环、不支持的引用和恢复后身份的语义。依赖【身份与相等性】【内存与引用模型】。

14-15 反序列化的权限与资源限制

  • 待讨论

确定输入能否指定类型或执行定制代码,以及不可信数据、超限输入和错误报告的默认规则。依赖【错误处理】【安全模型,如有】。

14-16 跨分类一致性验收

  • 待讨论

用一组完整例子核对反射、权限、表示、恢复与相关分类的规则;记录并解决冲突及阻塞。

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

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

当前仍在讨论 14-01:普通程序拿到一个陌生值,默认能查询多少结构信息? 例如,检查工具能否直接知道 Account 有 name 和 token 两个字段?

下面是相关语言的对照。取舍和启发是我们的分析,不代表这些语言的历史设计动机。

语言 规则与具体行为 好处、代价及对我们的启发
Python 许多普通实例可用 vars(x) 取得属性字典;没有 __dict__ 的值会报 TypeError。dir(x) 可以被定制,也不保证列出完整、准确的属性集合。官方文档 · dir 通用检查很方便,但“列出名称”“实例存储”“所有可访问属性”并不相同。启发:不能只设计一个含糊的“查看所有字段”操作。
JS Reflect.ownKeys({name: "林"}) 返回 ["name"],枚举自身属性键,包括不可枚举属性和 Symbol。#token 私有元素不属于普通属性,不会这样列出。ECMAScript 规范 · 私有元素 对普通属性默认可检查,适合动态工具;代价是这些名称成为可观察行为。启发:可以对普通数据开放反射,同时为私有状态设置独立边界。
TS 类型注解、接口等静态信息通常被擦除。例如 interface Account { name: string } 不会自动产生可供运行时查询的接口描述;运行时仍使用 JS 的机制。官方文档 静态检查不必带来完整运行时元数据成本;代价是运行时校验、按接口生成表单等功能需要额外描述。启发:查询对象现有属性与查询静态类型定义必须分开。
Go 标准库 reflect 能查询结构体字段,包括未导出字段的描述。但取得描述不等于取得全部操作权限:对来自未导出字段的值调用 Interface() 会 panic,修改还受 CanSet() 等条件限制。官方文档 通用工具能使用结构元数据,但必须处理权限和操作前提。启发:知道字段存在、读取字段值、修改字段是不同能力。
Rust 稳定版标准库的 Any 支持类型识别及向具体类型转换,例如 x.is::<Account>();它不提供通用字段枚举。#[derive(Debug)] 可以生成调试输出代码,这本身不等于开放字段反射。实验性的编译期反射另当别论。Any 文档 · derive 文档 可以按需提供能力,避免要求所有值都携带通用字段描述;代价是通用工具需要显式适配或生成代码。启发:调试打印可以独立于运行时结构反射存在。

这些实践不能直接一一对应我们的选项。一门语言可以同时采用不同规则,例如:普通属性默认可枚举,静态接口被擦除,调试表示又通过显式生成提供。

回到 14-01,我们的三个方向仍是:

  • A.不保证通用结构反射:陌生值只能通过主动提供的接口接受检查。语言承诺较少,通用工具需要更多适配。
  • B.显式参与结构反射:只有声明参与或提供描述的值,才能通过统一机制检查。暴露范围可控,但需要维护描述。
  • C.默认提供结构反射:对适用的结构化值,默认保证可以查询结构;访问权限另外规定。通用工具方便,但元数据需要成为语言承诺的一部分。

我仍建议先考虑 B:它让我们能够分别决定反射、调试和序列化的能力。不过语言用途尚未确定,这只是建议,尚未采用。

如果选 B,我建议同时确定两个验收边界:“没有反射描述”必须区别于“有描述但没有字段”;已经承诺可查询的描述,发布构建不能静默裁剪。 权限规则留给 14-07。

你倾向 A、B、C 中哪一个?如果选 B,是否一并接受上面两个边界?

讨论来源

《语言设计 14:反射与表示》,整理日期 2026-10-28。章节编号沿用原清单。