Appearance
运行时与内存模型
目标
Qlang 的内存模型必须同时满足三件事:
- 大多数开发者不需要显式写生命周期
- 生成的代码仍然接近系统级性能
- FFI 边界上的所有权关系足够清晰
这决定了它不能简单照搬 GC,也不能把完整 borrow checker 语法直接推给用户。
总体方案
Qlang 采用“值语义优先 + 所有权推断 + 受控共享”的混合模型。
默认规则
- 普通值默认按值传递
- 复杂对象默认仍遵循唯一所有权
- 编译器自动决定移动、借用或复制
- 只有在跨任务共享、引用计数或 FFI 边界时,才显式引入共享语义
编译器负责的复杂工作
- 自动借用
- 非逃逸值的栈分配
- 短生命周期对象的区域分配
- 移动后使用检查
- 析构顺序推导
共享与可变性
为了防止“看似简单,实际到处别名”的问题,Qlang 不鼓励裸共享可变引用。
推荐模型
- 单线程局部可变:
var - 跨作用域共享只读:
Shared[T] - 需要循环引用:
Shared[T] + Weak[T] - 并发共享可变:
Mutex[T],RwLock[T],Atom[T] - 更高层并发隔离:
actor
为什么这样设计
这能把“共享”和“可变”拆开,让数据竞争分析有稳定基础,也使 LSP 能给出更可靠的修改影响提示。
析构与资源释放
Qlang 应支持确定性析构:
- 作用域退出时自动释放拥有的资源
defer用于显式清理顺序控制- FFI 资源需要通过包装类型接入析构机制
这对文件句柄、套接字、锁、映射内存尤其重要。
与 GC 的关系
Qlang 核心语言不引入必选 GC。原因很直接:
- FFI 成本更高
- 布局与生命周期不够可控
- 系统编程场景中容易引入延迟不确定性
但是这不意味着完全拒绝托管能力。后续可以通过库和编译器插件提供可选区域分配器、arena、pool 或受控 GC 域,而不是把 GC 做成所有程序的强制前提。
与 Rust 的差异化
Qlang 不是要否定 Rust 的所有权模型,而是想在工程体验上做一次再平衡:
- 生命周期尽可能不出现在日常代码里
- 自动借用比显式借用更常见
- 诊断要更偏向“告诉你怎么改”
- 公共 API 保留足够强的语义约束,内部实现尽量少仪式感
需要尽早验证的高风险点
- 所有权推断是否会造成报错不稳定
- 区域分配与异步任务边界如何兼容
Shared与对象布局优化之间如何平衡- FFI 句柄包装在零成本和安全性之间如何权衡
这些问题会在原型阶段通过小型编译实验尽早打样,而不是拖到后面一次性爆炸。