Carbon 语言包声明语法统一提案解读:`package`/`library` 声明中 `impl` 修饰符前置与 `api` 关键字移除

Carbon 语言包声明语法统一提案解读:`package`/`library` 声明中 `impl` 修饰符前置与 `api` 关键字移除 Carbon 语言包声明语法统一提案解读package/library声明中impl修饰符前置与api关键字移除【免费下载链接】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 LanguageCarbon 实验性编程语言仓库中的设计提案 proposals/p003927-more-consistent-package-syntax.md对应 PR #3927该提案调整了包声明语法使其与 Carbon 其他声明如impl fn及 C module 语法风格保持一致。读完本文你将掌握Carbon 中 API 文件与实现文件impl 文件的两种新旧包声明写法、api关键字被移除的完整来龙去脉含 proposal #752 的影响、impl修饰符前置背后的设计权衡以及这些语法在 toolchain/parse/testdata/packages/package/ 测试与 core/prelude 源码中的实际落地方案。一、提案背景Carbon 的包与库组织方式Carbon 采用“包package— 库library— 文件file”的三层组织模型。一个包可以包含多个库每个库由一个API 文件API file与任意数量的实现文件implementation file即 impl 文件组成。API 文件定义对外公开的接口实现文件包含库内部实现细节。在源码仓库中可以看到这一模型的直接体现core/prelude/copy.carbon 以package Core library prelude/copy;声明自己属于Core包中名为prelude/copy的库同目录下其他文件如default.carbon、destroy.carbon则以package Core library prelude/...声明各自所属的库。旧语法的问题在本提案之前包声明的写法是[package Foo] [library bar] api; [package Foo] [library bar] impl;即用后缀式的api/impl关键字标记文件类型。提案认为这种写法与 Carbon 的通用声明语法不一致主要体现在两点修饰符位置不一致Carbon 中其他声明的修饰符关键字都位于引入关键字introducer keyword如fn、class、impl之前。例如impl fn声明中impl在最前。而包声明却把api/impl放在末尾。api强制冗余对大多数声明而言Carbon 默认公开defaultpublic以优先保证公共接口的可读性但 API 文件声明中api关键字是强制的使库接口比必要情况更冗长。二、新语法impl前置api移除提案的核心变更可用一张对照表概括文件类型旧语法新语法API 文件package Foo api;package Foo;API 文件指定库package Foo library bar api;package Foo library bar;实现文件package Foo impl;impl package Foo;实现文件指定库package Foo library bar impl;impl package Foo library bar;其中方括号[...]表示可选部分。变更要点如下移除api关键字与 #752 中“API 文件默认公开default public”的规则一致定义公共接口的方式就是“什么都不写”。impl变为修饰符并前置impl关键字被改造为声明修饰符modifier keyword与它在impl fn声明中的用法一致移动到声明最前面。文档术语统一在文档中统一称 API 文件为 “API files”实现文件为 “implementation files”不再混用 “apifiles” 与 “implfiles”。新语法在仓库中已有完整的解析测试支撑例如 toolchain/parse/testdata/packages/package/impl.carbonimpl package Geometry;以及带库名的形式见 toolchain/parse/testdata/packages/package/impl_library.carbonimpl package Geometry library [[TEST_NAME]];从解析输出的语法树可以看到impl被解析为ImplModifier节点、紧接着PackageIntroducerpackage关键字整个声明以PackageDecl ;结束。这印证了“修饰符位于引入关键字之前”的语法定位。三、为什么会演变成这样两份提案的历史沿革3.1 起点Proposal #107 代码与名称组织当前语法的雏形由 proposal #107: Code and name organization 引入。当时 #107 曾考虑过省略api关键字但最终放弃理由是我们考虑过从命名中去掉api但那会形成“从关键字的缺席来定义”的局面。而且如果impl和test都必须是强制的唯独api被排除在外会显得奇怪。我们更偏好更显式的名称。也就是说旧语法选择强制api核心顾虑是“由缺失推断含义”不够显式并担心与当时设想的test文件尚未实现不一致。3.2 转折点Proposal #752 API 文件默认公开促使本提案改变的根本原因是 #107 之后的两个后续变化#752 移除了api关键字标记导出名称的用法。#752 确立新规则声明默认属于公共 API用显式关键字标记非公共声明如private。这样一来api关键字在除包声明外的所有场景都被移除包声明成了唯一残留的api使用点。原文This removed all uses of theapikeyword other than in package declarations.修饰符关键字规则逐步成型各种提案陆续确立了“修饰符关键字位于引入关键字之前”的通用句法约定。包声明的后缀式api/impl由此成为孤例。另外当初作为“保留api强制写法”理由之一的test文件设想始终没有落地且未来即便落地也可以走“修饰符”路线例如在 API 文件中用test修饰符标注仅测试使用的函数与类型。因此“test 文件”不再构成维持旧语法的坚实理由。关于 #752 的可见性语义还可参阅其“备选方案”部分它明确对比了“默认 private”“impl 默认 public”等方案最终决定API 文件默认 public、impl 文件默认 private以保持与类成员“默认 public”行为的一致性。四、新语法在工具链中的实际落地新语法并非停留在纸面Carbon 工具链各阶段均有对应实现与测试证据4.1 解析阶段Parse测试用例toolchain/parse/testdata/packages/package/impl.carbon 验证了impl package Geometry;的解析并包含两个歧义消解disambiguation用例impl_disambiguate.carbonimpl package DisambiguateImpl;后的impl i32 as Interface {}会被正确解析为独立的 impl 声明而非包声明的延续impl_package_disambiguate.carbonimpl package DisambiguateImplPackage;后的impl package.Name as package.Interface {}同样被正确区分。数据结构toolchain/parse/tree.h 中PackagingNames结构带有is_impl布尔字段toolchain/parse/context.h 中的set_packaging_decl(packaging_names, is_impl)负责写入用于记录该文件是否为 impl 文件。4.2 语义检查阶段Check在 toolchain/check/check.cpp 中可以看到包/库名称被组织为ImportKey由包名与库名组成文件自身的打包信息通过parse_tree().packaging_decl()获取。实现文件会自动获得对同一库 API 文件的隐式导入impl package Cpp场景下有专门的注释说明这正是提案“Rationale”中提到“impl 文件缺少对『真实』API 文件的隐式导入”会被快速发现的机制基础。4.3 语义 IR 阶段SemIRtoolchain/sem_ir/file.h 中定义了判断当前文件是否为 impl 文件的逻辑// Returns true if this file is an impl. auto is_impl() - bool { return import_irs().Get(ImportIRId::ApiForImpl).sem_ir ! nullptr; }即如果一个文件关联了ApiForImpl导入它就是一个 impl 文件。这从实现层面印证了“实现文件必然对应一个 API 文件”的模型。五、设计依据为什么值得这样改提案的 Rationale 部分从 Carbon 的项目目标出发论证了该变更5.1 代码易读、易懂、易写Code that is easy to read, understand, and write可读性与可写性的小提升API 文件声明不再需要强制写api接口部分更简洁。声明间更一致所有声明的修饰符都统一在引入关键字之前。轻微风险可控确实存在“因为漏写impl修饰符而把实现文件误判为 API 文件”的小概率风险但该风险容易被快速发现途径包括文件命名约定实现文件缺少对“真正”API 文件的隐式导入工具链对重复 API 文件的检测。5.2 与 C 代码的互操作与迁移Interoperability with and migration from existing C code新语法与 C modules 的module Foo实现单元vsexport module Foo接口单元风格略为一致——C 也是在前置位置使用关键字。不过要注意方向相反C 默认不导出因此带关键字的那个export module对应的是导出接口而 Carbon 默认公开/导出带关键字的那个impl package对应的是非公开实现。这一“默认方向相反”的规律同样适用于 Carbon 的所有其他声明。六、备选方案为什么没走其他路线6.1 备选一强制api或impl作为后缀即维持旧语法。提案的取舍逻辑已在前文“历史沿革”与“Rationale”中展开。此外该备选方案还顺带给出了一个有力论据——新语法让impl package与import package的句法对齐impl package Foo library bar; import package Baz library quux;两者都采用前置关键字 包声明的统一模式同时预告未来讨论中的import reexport package ...或export import package ...语法也会沿用此前缀式约定。附带收益默认库default library的 Main 包声明退化为纯粹的;旧语法下是api;。虽然仍保留“该场景下省略整个包声明”的规则但既然被省略的声明仅由一个分号组成这条规则在语义上更易自洽。6.2 备选二把impl放在library之前另一种思路是让impl修饰library部分而非整个包声明得到形如package Foo impl library bar; package Foo impl; impl library bar;虽然这种做法在逻辑上有其自洽解释但缺陷明显impl关键字的位置会在开头、中间、结尾之间飘忽不定反而造成不一致无法与import对齐——import导入的是库library而非包package同样的论证在那里并不成立。因此该方向被否决。七、总结impl包声明语法统一提案的核心脉络可归纳为#107 确立的强制api后缀语法在 #752 移除api关键字其他用途、修饰符前置规则逐步成文之后已沦为孤例本提案顺势移除api、将impl前置为修饰符既减少了接口声明的冗余又让impl package、import package乃至未来的 reexport 语法保持统一的“前缀式”句法。工具链的解析测试、PackagingNames.is_impl数据结构和SemIR::File::is_impl()实现均已印证新语法的落地。如果你正在编写 Carbon 库代码请直接采用新语法API 文件写package Foo;或package Foo library bar;实现文件写impl package Foo;或impl package Foo library bar;。延伸阅读proposals/p000107-code-and-name-organization.md包/库/文件组织模型的原始提案proposals/p000752-api-file-default-public.mdAPI 文件默认公开规则本提案的直接前置proposals/p002550-simplified-package-declaration-for-the-main-package.mdMain 包简化包声明docs/project/goals.mdCarbon 语言设计目标core/prelude使用package Core library ...新语法的真实源码示例toolchain/parse/testdata/packages/package/包声明解析测试数据【免费下载链接】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),仅供参考