类型系统总纲
本文档作为 Dujie 类型系统的总纲,面向语言设计者和编译器开发者。
它的目标不是一次性定完所有细节,而是先建立统一的讨论边界、术语和问题拆分方式。后续涉及 any、opt<T>、类型推导、类型转换、拷贝语义等问题时,都应以本文为入口,再拆分到专题设计文档。
泛型相关问题不在本文中深入展开。本文只在必要处说明“类型系统与泛型系统的边界”,具体的泛型参数、约束、推导和实例化规则,后续统一放到独立文档中讨论。
语言目标
当前将 Dujie 定位为:
- 只用于描述 UI 的 DSL 语言
- 当前不实现响应式系统,但不封死未来扩展空间
这个目标直接约束类型系统的取舍:
- 优先保障组件描述、状态表达、属性传递和局部转换的易用性
- 优先支持文本、数值、布尔、容器、可选值和组件类型
- 不以通用系统编程语言为目标
- 不以底层二进制处理能力为核心目标
设计目标
提供稳定、可预测的静态类型检查
让常见 UI DSL 场景写法足够简洁
控制隐式规则数量,避免“看起来能写但解释不清”
将语言层面的类型规则与 Rust 后端实现细节分离
为后续泛型、约束和内建类型扩展保留空间
非目标
当前阶段不追求以下能力:
- 复杂的全局 Hindley-Milner 式类型推导
- 用户自定义子类型体系
- 隐式自动装箱/拆箱
- 依赖运行时反射完成常规类型检查
- 由 Rust 实现细节直接反向决定语言语义
- 面向底层二进制处理的完整原语集合
类型系统范围
本文讨论的类型系统范围包括:
- 类型种类
- 类型语法
- 类型检查
- 类型推导
- 类型转换
- 内建特殊类型的语言语义
- 与泛型系统的边界
本文暂不直接规定:
- 具体 CST / AST 节点长什么样
- Rust 代码生成的最终映射方式
- 标准库 API 的完整清单
- 泛型系统的完整规则
这些内容可以被本文约束,但不应反过来主导本文。
基本立场
1. Dujie 是静态类型语言
变量、表达式、函数参数、函数返回值、结构体字段都应在编译期拥有明确类型。
2. 类型规则优先于运行时实现
例如某个类型最终映射为 Rust 的 Arc<T>、Vec<T>、Option<T> 或 Box<dyn Any>,这是实现策略,不应直接替代语言语义定义。
3. 显式优先于隐式
除非有非常强的收益和非常低的歧义,否则类型变化应通过显式语法表达。当前可暂时接受的隐式行为,只应限于明确、局部且容易解释的规则,例如 T -> opt<T> 的局部提升。
4. 绑定可变性与类型身份分离
let / var 首先描述绑定是否允许重新赋值,不应混同为“变量所属类型是否会变化”的另一套机制。变量一旦完成类型确定,后续赋值必须与该类型兼容。
类型分类
当前讨论中,Dujie 的类型至少可分为以下几类:
1. 基础类型
intfloatboolrunestring
当前阶段只保留一个公开整数类型:int。
当前不把 byte 作为核心基础类型纳入默认类型系统范围。原因是 Dujie 的目标是 UI 描述和状态建模,而不是原始二进制处理语言。
2. 参数化容器类型
list<T>map<K, V>opt<T>iter<T>
本文后续将这组类型统称为“容器类型”。
3. 名义类型
struct
结构体属于语言层的命名类型系统,不应只被视为某种容器的语法糖。 它可以包含其他值,但不归入这里的“容器类型”。
4. 领域特殊类型
widget
widget 是为 UI DSL 提供的内建领域类型,需要与普通数据类型区分看待。
5. 边界类型
any
any 的职责、边界和允许出现的位置需要单独收敛,不应草率地把它当成“万能类型”。
当前不优先引入的类型
byte
在当前语言目标下,byte 不是优先类型。
原因:
- UI DSL 的主数据模型不是字节流,而是文本、状态、属性和组件树
- 即使未来引入响应式能力,其核心问题仍然不是字节运算
- 过早引入
byte会扩张数值类型设计、转换规则和容器语义
如果未来出现明确的二进制场景,例如资源加载、编码处理、哈希或网络协议边界,再单独讨论是否需要:
bytebytes- 或更高层的二进制抽象类型
与泛型系统的边界
类型系统总纲需要承认泛型系统会存在,但不在这里深入定义其完整机制。
当前只约定以下边界:
- 本文可以讨论“哪些类型位置未来允许出现类型参数”
- 本文可以讨论“某类能力要求是否存在”
- 本文不展开泛型参数声明语法
- 本文不展开约束系统的完整定义
- 本文不展开泛型实参推导和实例化规则
例如:
list<T>、map<K, V>、opt<T>、iter<T>这类参数化类型,会在本文中作为类型构造器讨论T: ...这样的约束语法,以及key这类约束的正式定义,放入独立的泛型系统文档
语义层面需要分离的几个概念
当前文档中有一些概念容易混在一起,后续必须拆开定义:
1. 类型类别 vs 运行时表示
“这是 list<T>” 与 “底层是否共享内存” 不是同一个问题。
2. 类型相等性 vs 类型兼容性
需要区分:
- 两个类型是否完全相同
- 某个值是否允许赋给某个目标类型
- 某个类型是否满足某个约束
3. 类型系统规则 vs API 设计
例如 scores["a"] 缺失键时返回什么,既涉及类型,也涉及容器 API 设计。两者要分层处理,不能只靠示例暗示。
4. 用户可见语义 vs 实现优化
比如“拷贝是否共享底层数据”如果要成为语言承诺,就必须写成正式语义;如果只是实现优化,就不应在用户文档里作为核心分类反复出现。
当前建议的总方向
在细节未完全收敛前,类型系统总方向先按以下原则推进:
以静态、显式、局部可推导为主
以名义类型和参数化类型为主,不引入复杂子类型体系
将 any 视为边界能力,而不是常规建模手段
将类型推导限制在易解释的局部上下文中
将“值/引用/共享/可变”等问题作为独立语义层处理,而不是先塞进类型名义体系
专题拆分与当前状态
当前总纲只保留稳定边界和术语,不再重复专题细则。
已经有明确专题承接的内容:
值语义与共享语义:见 11.value-and-sharing-semantics
函数参数、opt<T>、默认值和调用规则:见 12.functions-and-calls
字面量、表达式、语句、类型推导边界、iter<T>、panic 和语言级错误模型:见 13.expressions-and-statements
模块、导入导出、路径规则和入口约束:见 14.module-system
widget、组件函数和渲染内建边界:见 15.render-intrinsics
any 的定位、is 收窄和动态边界:见 16.any-design
泛型系统:见 10.generics-system
仍然值得继续单开文档细化的议题:
- 类型转换与标准库格式化/解析的分层
泛型相关内容继续独立处理,不并入本总纲。
与现有文档的关系
00.guide/03.data-types目前主要是面向使用者的说明,不是最终的设计依据01.design/06.struct-design当前只覆盖结构体的一部分实现思路,不能替代整体类型系统设计01.design/07.comparable-constraint是历史设计记录,不能替代当前的泛型约束设计01.design/12.functions-and-calls收敛函数参数、默认值和调用规则01.design/13.expressions-and-statements收敛字面量、控制流、运算、推导边界和语言级错误模型01.design/14.module-system收敛模块、导入导出、路径规则和入口约束01.design/15.render-intrinsics收敛widget、组件函数和渲染内建边界01.design/16.any-design收敛any的定位、边界和显式收窄规则
当前结论
当前阶段的工作方式保持不变: