资讯详情

资讯详情

Mojo 语言演进实录:`let` 声明移除提案(remove-let-decls)的设计论证与仓库落地验证

Mojo 语言演进实录let声明移除提案remove-let-decls的设计论证与仓库落地验证【免费下载链接】mojoThe Modular Platform (includes MAX Mojo)项目地址: https://gitcode.com/GitHub_Trending/mo/mojo本文基于 Mojo 语言提案《Simplifying Mojo - lets get rid oflet》作者 Chris Lattner2023 年 12 月Status:Accepted展开。该提案是 Mojo 早期语言设计中最具代表性的简化决策之一彻底移除具名不可变变量let仅保留var与def中 Python 风格的隐式声明并把不可变性收束到借用参数borrowed arguments与未来的不可变引用immutable references上。读完本文你将完整理解该提案的动机、论点、分阶段落地计划以及它在当前仓库发布记录v0.24.1、v0.24.2、v0.24.4中的真实执行结果可直接用于理解 Mojo 现代语法var/alias体系的来龙去脉。一、背景Mojo 0.6 时代的let/var双关键字设计Mojo 在开发早期沿用了 Swift 的先例允许程序员用let与var两个关键字自行决定某个局部名字是否可修改。提案明确指出Mojo 0.6 及更早版本中的这一设计存在一系列特别令人意外且不讨喜particularly surprising and unfortunate的方面归纳起来有八条对 Python 程序员完全是陌生概念。具名不可变变量对 Python 程序员而言是全新概念而 Swift 的实践经验表明这往往成为 Swift 初学者需要学习的第一个概念Constants and Variables。但具名不可变变量并非核心编程概念也不是达成 Mojo 目标所必需的。let的命名引发大量早期争论。let、val、const等关键字在不同语言如 C/C、JavaScript 的const中各有取舍let的命名本身就是一个持续消耗社区精力的 bikeshed 话题。与编译期值alias概念重叠。Mojo 还拥有编译期值compile time valuealias因此同一套语言里同时存在alias、let、var三个相近概念。多数场景下其他语言如 JavaScript中用const表达的意图在 Mojo 中用alias表达反而更贴切。与 Python 的设计重心相悖。Swift 与 Rust 都鼓励不可变Swift以及当时的 Mojo会对不必要的可变性发出警告Rust 则让可变性更啰嗦let mut。而 Python 压根没有这个概念——若 Mojo 将不可变设为默认会显得怪异若不做默认又何必保留它。没有可验证的性能收益。提案作者明确表示没有看到任何数据显示let/var区分能带来安全或可读性收益。唯一的论点是看到let x foo()时知道x永不被重新赋值但这种收益很小。引用语义类型下极度困惑。不可变性只作用于局部值本身对引用语义类型如当时的Pointer以及未来 Mojo 的所有类会造成强烈误导。社区高频提问我明明在修改指针指向的目标为什么警告我该把var指针改成let不允许let作为结构体字段规则不一致。Swift 为结构体字段初始化制定了非常复杂的规则Mojo 并不想复刻。同时默认字段值也没有好的定义方式例如提案中的设想代码struct Thing: # 当前并不支持但可以设想 let field 42 def __init__(out self): self.field 17 # 是否不应允许覆盖 field与所有权/生命周期体系形成概念叠加。Mojo 拥有所有权ownership概念未来还会有生命周期lifetimes与安全引用包括可变与不可变引用。不可变性以多种形态漂浮在语言中并不健康而不可变借用与不可变引用恰恰是真正需要的。提案作者还以 Swift 主要设计者之一的身份做了主观反思Swift 为了提升安全而加入了不少相当挑剔的语言特性例如要求所有可能抛错的值用try标记且许多早期决策缺乏数据支撑。因此应尽力让 Mojo 保持易学并尽可能消除多余概念。二、提案核心彻底消除let声明提案的核心主张非常直接彻底消除具名不可变值这一概念。这并不会消灭 Mojo 中的不可变性而是把它推入借用参数与不可变引用的世界中。该决策同时带来两大块收益简化概念模型消除 Python 程序员必须学习的一个陌生概念直接消除let与alias之间的混淆消除关键字命名之争keyword bikeshedding这一争论源泉消除工作簿workbook中顶层值声明为let却实际上可变的困惑。削减编译器复杂度错误信息不再需要小心翼翼地分辨该说let还是varIR 表示不再需要为后续语义检查跟踪该信息无需再为支持let而实现缺失的功能无需再实现检测未被修改的var并警告改成let这一整套逻辑由于 ASAP 析构ASAP destructionCheckLifetimes不得不额外增加复杂度去拒绝形如let x: Int; x 1; use(x); x 2; use(x)的代码——尽管第一个x 1的生命周期天然结束、x在再次赋值前本就处于未初始化状态。提案认为这始终是一个设计瑕疵且实际实现效果并不正确。提案同时给出明确结论该提案就目前所知不会对运行时性能产生任何影响——移除的是语言层面的语法与语义负担而非底层执行能力。补充提案中提到的未来的 lifetimes 特性在当前仓库中已有对应设计文档 lifetimes-and-provenance.md与不可变性主要落在借用与引用层面的路线一脉相承。三、var何去何从提案明确表示如果移除let应原样保留var。理由有二与传统 Python 行为不同var引入的是显式声明且词法作用域lexically scoped的值——Mojo 需要某种引入符introducer也确实需要作用域声明var这个名字争议更小因为它比let代表具名常量更清晰地表示变量variable。若有人想重命名var那是与本提案正交的独立讨论应分开进行。四、平滑落地四阶段推出计划为了让社区迁移更平滑、破坏性更小提案设计了一个分阶段推进路线阶段一——社区共识与 Mojo 社区建立共识收集反馈与额外视角阶段二——工程验证与警告期完成工程工作验证不存在性能回退并移除let的 IR 表示与行为。此阶段仍保留对let的解析以维持兼容将其解析为与var相同的 IR但发出警告let已被弃用将在下个版本移除并附带把let重命名为var的 fixit 提示阶段三——约 1 个月后把警告升级为错误阶段四——约 1 个月后再过一版连同错误信息一起彻底移除该关键字。五、替代方案保留并日后重估提案也考虑了替代方案可以一直保留let并在日后重新评估。但作者判断届时不会有任何变化——Modular 内外部的 Mojo 用户社区已经多次踩到这些问题这一问题会持续出现。该提案最终被标记为Accepted已接受并在后续版本中落地。六、仓库实证提案在发布记录中的真实落地过程原提案是设计蓝图而当前仓库的 release notes 则记录了它的完整执行轨迹——恰好严格遵循了警告 → 错误 → 彻底移除的三步节奏v0.24.1编译器移除let声明支持v0.24.1.md 的 Changed 章节写明作为移除 let 声明的一步我们已在编译器内部移除对 let 声明的支持。为便于迁移我们把let声明解析为var声明因此你的代码不会损坏。我们会对此发出警告但请显式改用var因为该迁移支持将在后续更新中移除。并给出示例fn test(): # 被当作 var 处理但请更新你的代码 let x 42 # 警告let 正在被移除请改用 var x 9v0.24.2警告升级为编译期错误v0.24.2.md 记载let声明现在产生编译期错误而非警告这是我们移除 let 声明的下一步。编译器暂时仍识别let关键字以便产生良好的错误信息但将在后续版本中移除。v0.24.4关键字从语法中彻底消失v0.24.4.md 宣告终点let关键字已从语言中完全移除。我们此前已移除let声明但仍保留错误信息现在它彻底从语法grammar中消失。这一演进路径与提案第五节Rolling out this proposal smoothly的设计完全吻合先在编译器内部消掉语义解析为var的 IR 警告 fixit再升格为错误最后连关键字与报错一起清除。七、现状观察var与alias的现代 Mojo 写法从当前仓库的代码可以直观验证提案落地后的语言形态——现代 Mojo 代码中不再出现let声明命名值统一由var运行时可变值与alias编译期值承担。例如标准库中的 rebind.mojo 展示了var在真实实现中的用法var lit ...、var rebound ...以及通过参数约定var src: src_type, out dest: dest_type表达可变/输出语义的方式。而alias则在 Mojo/stdlib/std 各模块如 anytype.mojo、simd.mojo、dtype.mojo 等中被大量使用承担编译期常量与类型别名的职责。由此可以确认提案落地后的清晰分工var声明一个显式、词法作用域、可重新赋值的运行时值alias声明编译期值常量、类型别名、编译期元数据不可变性不再以具名不可变变量形式出现而是交由借用参数borrowed与引用语义表达def函数保留 Python 风格的隐式变量声明。对于从旧版本 Mojo 迁移的开发者迁移路径同样清晰把let x ...直接改写为var x ...语义等价只是不再有不可变保证把原本想表达编译期常量的let改为alias若确实需要不可变的借用视图则依赖借用参数与未来的引用/生命周期特性参见 lifetimes-and-provenance.md。结语一次教科书式的语言简化决策remove-let-decls提案的价值不只在删掉一个关键字本身更在于它示范了 Mojo 语言设计的方法论以 Python 程序员的心智模型为锚点以编译器复杂度为成本核算以社区反馈为验证闭环以分阶段发布控制迁移阵痛。从 提案文档 到 v0.24.4 发布说明 的完整闭环既是 Mojo 早期语言演进的一段真实历史也是理解现代 Mojo 语法体系中var与alias分工的最佳切入点。【免费下载链接】mojoThe Modular Platform (includes MAX Mojo)项目地址: https://gitcode.com/GitHub_Trending/mo/mojo创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →