ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Carbon Language 函数返回类型推断:`auto` 返回类型的设计、规则与演进(Proposal 826)

Carbon Language 函数返回类型推断:`auto` 返回类型的设计、规则与演进(Proposal 826) Carbon Language 函数返回类型推断auto返回类型的设计、规则与演进Proposal #826【免费下载链接】carbon-langCarbon Languages main repository: documents, design, implementation, and related tools. (NOTE: Carbon Language is experimental; see README)项目地址: https://gitcode.com/GitHub_Trending/ca/carbon-lang本文基于 Carbon Language 仓库中的正式提案 Proposal #826: Function return type inference系统讲解 Carbon 如何为函数引入auto返回类型推断它要解决的问题、核心语法规则必须显式返回、禁止直接递归、不支持分离的声明与定义、背后的语言目标权衡以及被否决的三类替代方案。结合仓库当前的设计文档docs/design/functions.md、docs/design/type_inference.md与工具链源码词法层 toolchain/lex/token_kind.def、语义检查层 toolchain/check/handle_function.cpp还可以看到该提案中的规则是如何一步步落到语言设计与编译器实现中的。提案要解决的问题提案 proposals/p000826-function-return-type-inference.md 开篇提出的核心问题是是否有更短的方式声明函数这个问题具体拆解为两个子问题是否应该让声明者declarer能够要求函数的返回类型从返回值中推断得出是否应该提供一种替代的函数语法在返回类型推断的简单场景下给出更简短的函数声明回答这两个问题就需要引入类型推断机制并决定它以何种形态嵌入现有的函数声明语法。背景既有语法与 C 先例函数声明的既有语法根据 Proposal #438: Add statement syntax for function declarationsCarbon 批准的函数语句语法是fn 标识符 ( 参数列表 ) [ - 表达式 ] { 语句列表 }而当时可执行语义executable semantics阶段实际支持的语法是fn 标识符 ( 参数列表 ) 表达式提案指出C 中就有类似的返回类型自动推断机制而的用法又反映了当时为 match 模式匹配matching临时讨论的语法。这正是本提案需要在“简洁性”与“语法一致性”之间做取舍的原因。Lambda 的边界Lambda 当时也在 Carbon 的讨论中但预计会采用不同的语法。该提案不试图处理 lambda 语法只是指出lambda 语法的决定可能会反过来影响函数声明语法以维持两者之间的“语法对等性”syntax parity。auto关键字的引入这是 Carbon 中第一个正式引入auto关键字的提案提案 #339: var statement 曾在备选方案中提及auto但并未正式提议该关键字不过var x: auto这类用例在 Carbon 中是被预期支持的因此本提案中的auto可以放在同一语境下考虑auto的命名和行为总体上与 C 保持一致。在仓库的当前词法实现中auto已是一个正式的保留关键字见 toolchain/lex/token_kind.defCARBON_KEYWORD_TOKEN(Auto, auto)const限定的前车之鉴C 的演进提供了一个重要教训C 最初为 lambda 使用“匹配返回类型”matching return type后来切换到基于模板实参推断定义的auto变量规则后者会丢弃const限定从而产生微妙的行为差异。提案特别提醒const在 Carbon 中彼时尚未定义因此这个坑需要预先留意。核心提案- auto返回类型提案的主体非常简洁fn标识符(参数列表) - auto {语句列表}即用新的auto关键字支持自动类型推断同时附带两条关键限制只允许一条 return 语句。提案明确避免为“返回类型不一致”定义处理规则不支持分离的声明与定义。因为声明必须具有已知的返回类型auto返回类型下无法先声明、后定义。这条“单 return”限制在后来的设计文档中得到了落实。docs/design/functions.md 的“Return specification”一节写明- auto表示应使用类型推断确定返回类型例如fn Echo(val: i64) - auto { return val; }的返回类型经推断为i64前向声明forward declaration必须有已知返回类型因此auto不合法函数必须恰好有一个return语句该 return 语句的表达式将用于类型推断auto前可加val、ref、var来指定返回的表达类别expression category。关键规则细节必须显式返回表达式使用- auto的函数必须返回一个表达式隐式返回函数体末尾自动返回或裸写return;都是非法的。这一要求与 Carbon 控制流设计中关于“返回空元组”returning empty tuples 的约定保持一致——空元组返回只能由省略-子句表达不能与推断返回类型混用。在工具链的语义检查层返回语句的处理集中在 toolchain/check/return.cpp其中BuildReturnWithNoExpr负责对“无表达式的 return”进行诊断BuildReturnWithExpr则负责将返回表达式与函数声明的返回形式return form做类型转换与一致性检查。auto推断场景正是走“必须有表达式”这条路径。移除可执行语义中的函数语法提案明确可执行语义将移除函数语法。也就是说现有写法fn Add(x: i32, y: i32) x y;将改写为fn Add(x: i32, y: i32) - auto { return x y; }需要说明的是仓库当前状态中这一移除尚未完全落地。docs/design/functions.md 目前仍将描述为“以- auto推断返回类型”的简写语法例如fn Add(a: i64, b: i64) a b;的返回类型基于表达式a b推断且因其返回类型是被推断的定义的函数不能有无定义的前向声明而在 check 阶段简洁函数定义的处理入口仍标记为待实现见 toolchain/check/handle_function.cppauto HandleParseNode(Context context, Parse::FunctionTerseDefinitionId node_id) - bool { return context.TODO(node_id, HandleFunctionTerseDefinition); }也就是说从源码结构看的“terse definition”节点在解析树中已有一席之地语义处理则处于过渡状态——这与提案中“移除函数语法”的长期方向并不矛盾只是体现了实验性语言实现随提案逐步收敛的过程。禁止直接递归直接递归调用会给返回类型推断带来复杂性。提案给出两类示例// 在 return 语句中递归。 fn Factorial(x: i32) - auto { return (if x 1 then x else x * Factorial(x - 1)); } // 在 return 语句之前但影响返回类型。 fn Factorial(x: i32) - auto { var x: auto (if x 1 then x else x * Factorial(x - 1)); return x; }第一种情况中return表达式的类型依赖Factorial自身的返回类型第二种情况中var x: auto的类型同样依赖它。因此提案的结论是直接递归被拒绝——即返回类型为auto的函数不允许调用自己。间接递归为什么不需要额外规则间接递归的典型形态是fn ExplicitReturn() - i32; fn AutoReturn() - auto { return ExplicitReturn(); } fn ExplicitReturn() - i32 { return AutoReturn(); }这是合法的AutoReturn()的返回类型可以从ExplicitReturn的前向声明算出来是i32。提案进一步论证由于名称查找name lookup的工作方式间接递归不会给类型推断造成麻烦理由有二auto返回类型不允许单独的前向声明见前文核心规则没有单独声明时名称查找会直接失败。例如下面的代码在return B();处就是名称查找错误fn A() - auto { return B(); } fn B() - auto { return A(); }因此与直接递归不同间接递归不需要专门的规则。基于 Carbon 语言目标的论证提案将设计决策锚定在 Carbon 的正式语言目标上见 docs/project/goals.md“易于阅读、理解和编写的代码”刻意不提供替代函数语法让用户少学一种需要理解的语法作为务实考量在泛型代码中auto返回类型往往使某些代码更容易写出来。“与现有 C 代码的互操作及迁移”有意让auto返回类型的行为与 C 的类型推断类似以降低从 C 迁移的门槛。开放问题多个 return 语句提案预期最终应当支持带多个 return 的函数使用auto但因返回类型可能不一致带来的复杂性本提案拒绝处理该场景留给后续提案。值得注意的是仓库中的设计文档已经朝这个方向演进docs/design/README.md 在“Common type”一节中写道带auto返回类型的函数其推断出的返回类型是其各个return语句表达式的公共类型common type该公共类型由CommonTypeWith接口的实现给出// A 和 B 的公共类型是 C。 impl A as CommonTypeWith(B) where .Result C { }且公共类型要求两个类型都能隐式转换到它。这表明“多 return 的auto推断”这一开放问题正在以公共类型机制的形态被逐步解决。const限定如背景部分所述C 在const限定上经历过变化。提案认为应当选择一个长期可行的方案这很可能要等到模板实参推断deduction for templates的规则被处理时再重新审视。被否决的替代方案仅当参数为泛型时才允许auto返回类型动机auto返回类型对可读性可能是负资产——读者必须读函数体才能确定返回类型。一种限制方案是只有当参与推断的参数是泛型generic时才允许auto。优点限制auto对可读性的影响——返回类型显然可确定的地方不许用auto那些地方本就容易手写返回类型只有在泛型参数使返回类型难以书写时才允许。缺点增加auto使用规则集破坏 C 兼容性。最终决定是允许auto用于更多场景主要理由就是 C 兼容性。这一备选在 docs/design/functions.md 的参考资料列表中仍被引用。提供简洁返回类型推断的替代函数语法即可执行语义中现有的fn Add(x: i32, y: i32) x y;优点对短函数提供更简练的定义方式与 match 的暂定语法呼应。缺点为等价行为引入额外语法与 lambda 用例重叠但 lambda 最终很可能长成不同的样子——不应假设两者会收敛。Lambda 语法甚至可能走得更激进、更简短而这种简写放在具名函数声明中未必合理占用这个记号的其他用途。如果主要是在替代- auto类似假设 Carbon 采纳 Rust 风格的块表达式返回值那么它作为额外记号的收益很有限。提案的结论是现阶段不加入推断导向的替代函数语法。虽然它与 match 的暂定语法一致但函数语法的割裂程度较大此处适用“one way”原则——即尽量让每一种行为只有一种写法。如果将来要加入替代函数语法应当与 lambda 提案同步推进以保证语法一致。仓库现状佐证了这一“与 lambda 同步”的思路lambda 提案 p003848 中大量使用let lambda: auto fn T.Make();这类写法并明确将fn 表达式定义为“等价于- auto { return 表达式; }”让 lambda 与函数声明共享同一套auto推断语义。允许分离的声明与定义返回类型必须能从声明处确定因此返回auto的函数其声明与定义不能显著分离——调用者必须能看到定义。一种折中方案是只要调用者能同时看到声明和定义就允许auto搭配分离的声明/定义。该方案下这个例子合法因为CallAdd能看到Add的定义fn Add(x: i32, y: i32) - auto; fn Add(x: i32, y: i32) - auto { return x y; } fn CallAdd() - i32 { return Add(1, 2); }而这个例子非法CallAdd只能看到Add的声明即使定义在同一文件里缺少定义就无法确定返回类型fn Add(x: i32, y: i32) - auto; fn CallAdd() - i32 { return Add(1, 2); } fn Add(x: i32, y: i32) - auto { return x y; }优点可以在文件中把简短声明聚集在前、定义放后面类声明中尤其常见提供声明、在类外定义以免打断类 API 的呈现。不过若auto返回类型只推荐用于短函数短函数本就可以内联这一优势有限。缺点无法用于打破调用循环——这正是分离声明/定义的常见用途。单独声明在定义给出之前依然不可被调用这对人类读者尤其容易造成困惑。最终决定不支持auto返回类型的分离声明与定义理由是其效用有限。这一决定与当前设计文档保持一致docs/design/functions.md 明确写着“前向声明必须有已知返回类型因此auto不合法”。提案的落地情况从设计文档到工具链综合仓库现状可以看到提案 #826 的内容在三层面上的落点词法层auto已登记为关键字toolchain/lex/token_kind.def这是所有后续语义的前提。设计层docs/design/functions.md 的“Return specification”一节完整吸收了提案的核心规则——- auto触发类型推断、恰好一条return、前向声明禁用auto、auto可被val/ref/var限定docs/design/type_inference.md 则声明“目前类型推断支持函数返回类型”并指出当前推断规则很简单给定产生值的表达式推断出的类型就是该表达式的精确类型。实现层函数签名含返回形式的构建集中在 toolchain/check/handle_function.cpp 的BuildFunctionDecl中它统一处理声明与定义两种语法形态并把return_type_inst_id、return_form_inst_id等字段存入SemIR::Function返回语句的语义检查含对“无表达式 return”“声明了返回类型却缺少 return”的诊断位于 toolchain/check/return.cpp 与 toolchain/check/handle_function.cpp函数体可达但未 return 时触发MissingReturnStatement诊断。小结提案 p000826 为 Carbon 引入了fn ... - auto { ... }这一返回类型推断机制其设计可以概括为四条硬规则加三项取舍必须显式return 表达式不支持隐式返回函数恰好一条 return 语句避免多返回类型不一致的复杂性禁止直接递归间接递归靠名称查找自然排除不允许auto返回类型的前向声明声明与定义不能分离不为简洁性引入等替代函数语法one way 原则、与 lambda 语法解耦不限制auto仅用于泛型参数优先保持与 C 的推断语义一致服务于 C 迁移目标。从仓库当前状态看auto返回类型已写入正式设计文档并在词法与语义检查中持续落地而提案遗留的两个开放问题——多 return 的公共类型推断与const限定——正分别通过CommonTypeWith公共类型机制和模板推断规则的后续工作被推进。【免费下载链接】carbon-langCarbon Languages main repository: documents, design, implementation, and related tools. (NOTE: Carbon Language is experimental; see README)项目地址: https://gitcode.com/GitHub_Trending/ca/carbon-lang创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表