Carbon 语言项目中的进行中设计总览(In-progress Design Overview):以docs/design为核心骨架的提案解读与实践指南
【免费下载链接】carbon-langCarbon Language's 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 仓库中的正式提案 proposals/p000083-in-progress-design-overview.md,深入讲解"进行中的设计总览"(in-progress design overview)这一文档体系的来龙去脉:它如何为 Carbon 语言的整体设计提供一个"模糊但连贯"的共同参照系,如何通过docs/design/多文件层级组织语言设计文档,以及该体系在后续提案与工具链实现中的实际演化。读者读完后,将理解 Carbon 的设计文档目录结构、总览文档的内容骨架(从基础语法到泛型、再到 C/C++ 互操作),以及这套"先搭骨架、再逐区域填充细节"的渐进式设计方法论,并能在当前仓库中按图索骥找到对应源码与测试佐证。
一、背景:为什么需要一份"进行中"的设计总览
1.1 问题:讨论中的一致共识
Carbon 作为一门正在实验中的编程语言(参见仓库根目录 README.md),其语言设计需要"某种大致一致的、对语言设计整体的共享理解"。提案 p000083 明确指出:
- 目标是让讨论、进行中的语法和总体方法保持一致;
- 它并不需要可靠地反映最终状态(无论是期望的还是已实现的);
- 相反,它应当随着每个设计区域的成熟而演化,同时提供连接语言各部分的总体概览和讨论时可反复参照的一致背景。
关键点在于"in-progress"(进行中)这一限定:这份总览不是一份冻结的规格说明,而是一份随设计推进会持续更新的活文档。
1.2 来源与经验背景
提案的 Background 部分说明,许多想法源于几位早期 Carbon 工作者数年间的讨论,并深受他们在 Clang C++ 前端以及 LLVM、Clang 自身代码库上的经验影响。这解释了为什么 Carbon 的设计文档会特别强调多文件层级与结构化组织——这与大型 C++ 项目(尤其是 LLVM 家族)中常见的"目录级文档 + 分区细化"的组织方式一脉相承。
二、目标与非目标:一份"骨架框架"的边界
2.1 目标:提供合理的起点
提案 p000083 明确这份总览意在为以下事项提供合理起点:
- 示例代码;
- 在高层概念层面认识 Carbon;
- 在 README.md 中为语言特性提供合理(但不一定是最终)的方法——如果某个想法明显有问题,可以在这里先清理掉。
2.2 非目标:不是完整的语言设计
提案同时划定了明确的边界:
- 不是完整的语言设计——单一提案完成全部设计工作量过大,这里只提供骨架框架;特性专属设计可以另起炉灶采用不同方法,总览只需提供起点。
- 特性专属文件不需要写得完美或面面俱到——它们只是"先前想法的快速记录",以避免在不值得纠结的语言细节上卡住;如果你对某特性充满热情,请为它启动一个新的提案。
- 建议总览中的每一个方面在成为定案计划之前,都要经过仔细检验和论证。
这套"骨架先行、细节后补"的理念,直接塑造了当前仓库中docs/design/目录的形态:它今天已经是一个包含十余个子目录、数百个文档与提案的庞大体系。
三、提案核心:docs/design多文件层级总览
3.1 提案内容
提案的 Proposal 部分非常简短,直接指向:
See the language design overview document.
即:用docs/design/README.md作为语言设计总览的主文档,并在其周围建立多文件层级结构。这正是本文后续要展开的核心骨架。
3.2 当前仓库中的实际目录结构
对照仓库现状,docs/design/已经成长为如下层级(这正是提案所预期的"复杂特性可拥有带自己 README.md 的子目录"的形态):
- 总览入口:docs/design/README.md(约 3864 行,覆盖语言设计全貌)
- 一级专题目录:
- code_and_name_organization(代码与命名组织:文件、库、包、命名空间)
- control_flow(控制流:
if/else、循环、return) - expressions(表达式:算术、位运算、比较、转换、索引等)
- generics(泛型:checked/template 参数、接口与实现、关联常量)
- interoperability(与 C/C++ 的双向互操作)
- lexical_conventions(词法约定:字面量、注释、字符串等)
- safety(安全)
- 顶层单篇设计文档:
aliases.md、assignment.md、classes.md、functions.md、pattern_matching.md、tuples.md、values.md、variadics.md、metaprogramming.md等。
从该结构可以推断:提案中"多文件设计"的原则——复杂特性应有子目录并配有自己的 README.md——已经被完整落地,例如expressions/下又细分为arithmetic.md、bitwise.md、comparison_operators.md、implicit_conversions.md、as_expressions.md等专门文档。
四、总览文档的结构解析:从基础到互操作的完整骨架
docs/design/README.md 是提案所指的总览主体。它明确声明自己是"面向 Carbon 的构建者以及对学习 Carbon 感兴趣者的当前状态概览",并不是完整的编程手册——详细论证都在链接的专门设计文档中。其目录骨架值得逐节梳理:
4.1 开篇导读与"临时性声明"
文档开篇即声明"This document is provisional"(本文件是临时的):其中的语法、语言规则、标准库等许多方面都尚未经过 Carbon 流程正式决定,临时材料用来填补设计空缺,且尽量标记了 provisional 特征。
随后给出了一段经典示例代码(SmallestFactor函数),作为 "Tour of the basics"(基础导览),覆盖:
import Core library "io"; import Math; // Returns the smallest factor of `n` > 1, and // whether `n` itself is prime. fn SmallestFactor(n: i32) -> (i32, bool) { let limit: i32 = Math.Sqrt(n) as i32; var i: i32 = 2; while (i <= limit) { let remainder: i32 = n % i; if (remainder == 0) { Core.Print("{0} is a factor of {1}", i, n); return (i, false); } ... } return (n, true); }这段示例依次展示了import声明、//注释、fn函数定义、var/let声明、while/if控制流、as显式转换、元组返回类型等基础概念——其中Core.Print在 core/prelude.carbon 的预置库体系中可找到对应实现。
4.2 构建模式(Build modes)
总览文档介绍了编译器行为的三种模式(详见 safety 设计):
- debug build:优先诊断问题与快速构建;
- release build:优先最快执行速度与最低内存占用;
- 整数溢出等行为在不同模式下的语义不同(如 hardened 模式下溢出不产生未定义行为,而是中止或回退到数学上不正确的结果)。
4.3 类型即值(Types are values)
这是 Carbon 与 C++ 的核心差异之一:类型本身被建模为类型type的编译期常量值。由此产生一系列推论:
- 类型名与函数、变量共享同一命名空间;
- 类型的书写语法就是表达式语法,因此不使用尖括号
<...>(避免与比较运算符冲突); - 类型参数用函数调用语法,如
HashMap(String, i64)。
该部分还讨论了"可用于类型位置的值"(values usable as types),例如元组(bool, bool)可通过隐式转换到type用作类型。
4.4 基本类型与字面量
bool:两个值true/false;- 整数类型:
iN/uN(N 为 8 的正倍数),如i32;十进制/十六进制(0x1FE)/八进制(0o755)/二进制(0b1010)字面量,支持下划线分隔符,且字面量不带类型后缀(与 C++ 不同,数值字面量类型由值推导); - 浮点类型:
f16/f32/f64(IEEE-754 语义、round-to-nearest),还支持BFloat16;实数(real-number)字面量如123.456、123.456e789、0x1.Ap123; - 字符串类型:
String(UTF-8 字节序列)与StringView(只读引用),支持块字符串字面量(''')与转义/原始字符串。
4.5 值、对象与表达式
- 表达式类别(Expression categories):值表达式(value,只读抽象值)、引用表达式(reference,指向有存储的对象)、初始化表达式(initializing,需要隐式提供存储)——并定义了四类原始转换步骤:值获取、直接初始化、拷贝初始化、临时物化;
- 表达式阶段(Expression phases):模板常量(template constant,编译期已知,可用于数组大小等)、符号常量(symbolic constant,单态化时已知)、运行时值(runtime value)。模板常量→符号常量→运行时值之间可自动转换。
4.6 复合类型
- 元组(Tuples):
(i32, i32),按位置访问x[0],结构性类型; - 结构体类型(Struct types):
{.name: String, .count: i32}为类型,{.key = "Joe", .count = 3}为字面量值; - 指针类型:
T*,不支持指针算术;无空指针,可空用Optional(T*);仅支持解引用*p、取址&x、p->m((*p).m的语法糖); - 数组与缓冲区:
array(T, N)(Core.Array简写)、堆分配动态数组buf(T)(Core.Buf简写); - 切片(Slices):标记为 TODO,尚未形成设计。
4.7 声明、定义与作用域
声明引入名字,函数等实体区分前置声明(forward declaration)与定义(definition);名字在最近的闭合作用域末尾前有效。作用域类型包括文件级、花括号包围块、单个声明。
4.8 模式(Patterns)
- 不可反驳模式(Irrefutable):如绑定模式
name: type,可用于函数参数、var/let声明;_通配;auto类型推断; - 可反驳模式(Refutable):如表达式模式、choice 模式、动态类型转换模式,主要用于
match; - 解构模式(Destructuring):如
var (p: i64, _: auto) = Bar();。
4.9 名称绑定声明
let x: i64 = 42;常量声明(初始值必填);var x: i64 = 42;变量声明(可修改、有地址);auto类型推断:let y: auto = x + 3;;- 全局常量允许,但当前没有全局变量(设计正在探索替代方案)。
4.10 函数
- 定义结构:
fn关键字 + 名称 + 参数列表 + 可选->返回类型 +{...}函数体; - 参数默认是
let绑定(输入参数);var前缀表示拷贝到新存储;输入/输出参数用指针; auto返回类型推断(从所有return语句的公共类型推导);- 控制流:
if/else、while、for(基于范围的迭代)、break、continue、return、returned var(避免返回拷贝)、match(类似 switch/Swift,支持带if守卫的 case)。
match示例(来自总览文档):
fn Foo() -> f32 { match (Bar()) { case (42, (x: f32, y: f32)) => { return x - y; } case (p: i32, (x: f32, _: f32)) if (p < 13) => { return p * x; } default => { return Pi; } } }4.11 用户定义类型
- 类(Classes):名义类型;字段用
var声明且字段顺序决定内存布局;Self指代类本身;支持非实例成员函数(类似 C++ static)、方法(self/ref self首参数)、继承(base class/abstract class,仅单继承,默认 final,virtual/abstract/impl方法修饰)、访问控制(默认 public,private/protected/friend)、析构器(fn destroy)、const限定类型、unformed 状态、移动语义(~x)、mixins(开发中); - choice 类型(Choice types):带标签的联合(tagged union),如
choice IntResult { Success(value: i32), Failure(error: String), Cancelled },可配合match消费,也可表示枚举。
4.12 名字(Names)
- 文件/库/包:文件构成库,库构成包;库是导入复用粒度,包是分发单元;每个库恰好一个 API 文件(.carbon),可有零或多个实现文件(.impl.carbon);
- package 声明:
package Geometry library "Shapes";,impl修饰表示实现文件;Main包的默认库定义程序入口Run函数; - import 声明:同包导入省略包名(
import library "Vertex";),跨包导入import LinearAlgebra library "Vector";;实现文件自动导入其库的 API 文件; - 名称可见性:API 文件默认 public,
private前缀为库私有,实现文件中的名字默认文件私有; - 命名空间:
namespace TwoDimensional;,包名本身是最外层命名空间(不存在"全局"命名空间); - 命名约定:
UpperCamelCase用于编译期已知实体(函数、命名空间、类型等),lower_snake_case用于运行时值(变量); - 别名:
alias NewName = SomePackage.OldName;(等号右侧是名字而非值); - 名称查找:在所有相关作用域中查找,若指代多个不同实体则报错——用限定符消除歧义,而非遮蔽(shadowing)。通用类型(
i32、bool等)通过自动导入的"prelude"包提供。
4.13 泛型(Generics)
- checked 与 template 参数:编译期绑定可标记为
generic(定义时即类型检查,查找委托给约束)或template(实例化时检查,晚绑定、鸭子类型,类似 C++ 模板但不使用 SFINAE,而是显式约束);fn MinT: Ordered -> T是典型 checked 泛型示例; - 接口与实现:
interface Printable { fn Print(self); },类型通过显式impl声明实现接口(有同名函数不足够);支持extend、复合成员访问c.(Printable.Print)()、forward declaration; - 组合约束:
T: Ordered & Printable,同名成员用复合成员访问消歧; - 模板名称查找:在调用方实际值中查找,加上约束;可安全地从 template 逐步添加约束迁移到 checked 泛型;
- 关联常量:接口中的
let ElementType: Movable;由where .ElementType = i32在实现中赋值; - 泛型实体:泛型类
class Stack(T: type)、泛型 choice、泛型接口interface AddWith(U: type)、泛型实现impl forall [T: Printable] Vector(T) as Printable;; - 其他特性:命名约束、模板约束、adapter 类型、
where约束、蕴含约束、计划中的动态擦除类型与可变参数; observe声明:用于声明两个类型相等(observe...==)或某类型实现某接口(observe...impls),帮助编译器在有限搜索深度下通过类型检查;- 运算符重载:运算符被改写为接口方法调用(
x + y→x.(AddWith(U).Op)(y)),并列出Add/Sub/Mul/Div/Mod、BitAnd等各运算符对应接口; - 公共类型(Common type):条件表达式、多参数推导、
auto返回类型推断都需要,通过impl A as CommonTypeWith(B) where .Result = C指定。
4.14 与 C/C++ 的双向互操作
- 目标:共享 C/C++ 代码与库生态、支持渐进迁移;其方法与 Java/Kotlin interop 最相似,共享内存模型;
- 非目标:不追求与纯 Carbon 工具链的完全对等、不承诺永不要求 bridge code 等;
import Cpp library "circle.h";导入 C++ 头文件;反向通过#include "geometry.carbon.h";- Carbon 本身没有稳定的整体 ABI,ABI 稳定边界将是显式 opt-in 的语言特性;对已编译 C++ 目标代码/共享库的互操作可能受限,但预计对 C ABI 提供完整支持;
- C++ 运算符重载与 Carbon 接口相互映射(如 C++ 的
operator%↔ Carbon 的ModWith(U)); - 标准类型映射:
bool↔bool、float↔f32、double↔f64、T*↔Optional(T*)、T[4]↔array(T, 4),std::string_view↔Core.Str; - C++ 模板的迁移路径:C++ 模板 → Carbon template → 加约束的 template → checked generic。
4.15 未完成的故事(Unfinished tales)
总览文档明确列出仍在规划中的区域:安全(Safety,目标是"在不牺牲性能的前提下通过编译期安全渐进获得")、生命周期与移动语义、元编程、将模式匹配作为函数重载解析、错误处理(当前用 choice 类型如Result/Optional表示)、执行抽象(抽象机、lambda、协程、并发,均为 TODO)。
五、方案取舍:三个被考虑的替代方案
提案 p000083 记录了三个替代方案的利弊权衡:
5.1 单文件设计总览(Single-file design overview)
来自 PR 22 的做法——把整个设计总览放进一个文件。
- 优点:所有提议的变更集中在一处;便于浏览理由与变更历史。
- 缺点:鼓励更多单文件设计;多文件原则认为复杂特性应有带自己 README.md 的子目录;单文件设计的信息量增长后会阻碍阅读、难以长期演化。
5.2 没有进行中的设计总览(No in-progress design overview)
等每个组成部分被更彻底地构思和审议后再开始写设计。
- 优点:避免把设计锚定在未经充分探索的方法上;避免卡在未成型的细节讨论上。
- 缺点:缺少总览会导致讨论中的混乱与不一致,反而阻碍细节成型——总览为语言整体提供基本塑形,即使它在演化中。
最终妥协:保留进行中的设计,同时努力抵抗它带来的锚定效应与分心——既获得总览的收益,又把成本降到最低。
5.3 没有设计总览(No overview of designs)
总览会与各独立设计产生内容重复(设计未成型时重复尤其明显,随成熟应减少,但因总览的本质而不会消失)。替代做法是把design/README.md退化为只列出已有设计的纯索引。
- 优点:消除内容重复;简单索引长期更易维护、不易过时,甚至可以完全自动化。
- 缺点:没有快速获得高层理解的途径(总览是"阅读全部设计"之前的唯一台阶,例如它汇总了常用控制流关键字);难以展示各特性间的关系(例如词法约定被三个本不相关的章节引用;类型类别之间的关系也无法从简单链接看出)。
提案最终认为:总览提供的 ramp-up 价值是显著的,值得保留重复。
六、Rationale:为并行化设计工作搭建共同框架
提案的 Rationale 部分总结了采纳这一方案的根本理由:
- 它给大量讨论与审议提供了急需的语境;在语言设计中"先有一个大图的模糊轮廓"是必要的,否则任何具体区域的设计都是在真空中进行的;
- 它建立了关于语言整体形态的共同参照系,从而可以并行化深入的设计工作;
- 因此,提案不可避免地建议了许多尚未充分分析的具体设计决策,但各方共识是:不承诺其中任何单项决策,只承诺这些决策组合所描绘的宏观图景;所有此类决策在被后续提案重新审视之前都不算达成一致;
- 存在把对 Carbon 的思考方式"锚定"下来的重大风险,团队必须尽力避免在评估后续提案时把本文档视为既成事实——后续提案既要为"与本文一致"的方向提供论证,也要为"与本文不一致"的方向提供论证;
- 采用这种"进行中"的总览,有助于强化"语言随时间的演化"这一目标,帮助团队学会如何有效迭代,并克服锚定效应、变更抗拒等挑战。
七、从提案到现实:仓库中的落地印证
7.1 目录结构的兑现
提案预期的多文件层级已在 docs/design 完整落地:总览 README 引用各专题目录,专题目录又有自己的 README 与细分文档。例如 docs/design/code_and_name_organization/README.md 详细展开包/库/命名空间的设计,并给出了package Geometry library "Shapes";、import Geometry library "Shapes";等完整语法与重构指南;docs/design/control_flow/README.md 则概述了if/else、while、for、break、continue、return六类控制流语句。
7.2 设计→实现的双向印证
设计文档并非空中楼阁,总览中的概念在仓库源码中能找到对应实现:
- 示例代码落地:总览中的基础语法(
fn、var、let、import、Core.Print)在 examples/hello_world.carbon、examples/sieve.carbon 等可直接运行,而Core.Print的实现在 core/io.carbon 与 core/io.impl.carbon; - 预置库(prelude):总览中"通用类型经 prelude 自动导入"的设计,对应 core/prelude.carbon 及 core/prelude 下的
types、operators子目录——例如i32、bool等类型与运算符接口的声明; - 工具链实现:语言特性在 toolchain 中有系统化实现,例如语法检查入口 toolchain/check/check.cpp 及其庞大的测试语料 toolchain/check/testdata;解析器在 toolchain/parse、词法分析在 toolchain/lex;
- 提案即设计的演进载体:仓库 proposals/README.md 说明,接受后的提案以
p######-slug.md形式归档于 proposals 目录——这正是总览文档中"每一项设计决策都要由后续提案重新审视"这一机制的物理体现。例如泛型设计由p000524-generics-overview.md、p000553-generics-details-part-1.md等一长串提案逐步细化,而互操作设计则由p000175-c-interoperability-goals.md、p006358-c-interop-api-importing-and-semantics.md等推进,每一环都在docs/design/对应目录下留下印记。
八、实践建议:如何阅读与使用这套总览
对想要深入了解 Carbon 的读者,可以按如下路径利用这套体系:
- 快速入门:通读 docs/design/README.md 的 "Tour of the basics" 与各节概览,获得语言整体形状;
- 专题深挖:按需进入对应专题目录,例如泛型从 docs/design/generics/overview.md 入手,再读
details.md与相关提案(如 proposals/p000524-generics-overview.md); - 对照实现:用 examples 下的可运行示例验证语法(例如 examples/hello_world.carbon),用 toolchain 源码与测试语料确认语义细节;
- 关注演进:留意总览文档中标记的
provisional、Note、TODO标注,它们是尚未定案、正在演进中的设计区域,也是新提案的潜在切入点。
需要强调的是,正如提案 p000083 所提醒的:总览反映的是"当前共识的宏观图景"而非最终承诺。在阅读、引用甚至参与设计时,都应把它当作一幅会持续修订的草图,而非一份冻结的规格。
结语
一份"进行中的设计总览",其价值不在于正确,而在于让一个大型语言的并行设计成为可能。Carbon 通过docs/design/README.md主总览 + 专题子目录 + 提案归档的三层结构,在"没有总览的混乱"与"过早定案的锚定"之间找到了平衡点。这份提案虽然短小,却为后续数百份设计文档与工具链实现铺设了组织骨架——理解它,就理解了 Carbon 设计文档体系的地图。
【免费下载链接】carbon-langCarbon Language's 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),仅供参考