RFC-0036:结构体声明更新 | |
---|---|
状态 | 已拒绝 |
区域 |
|
说明 | 为了更好地传达重新排序和重命名字段的 ABI 影响,我们提议进行语法更改,以便为结构体字段引入序数,其语法规则与表的语法规则类似。 |
作者 | |
提交日期(年-月-日) | 2019-03-07 |
审核日期(年-月-日) | 2019-03-14 |
拒绝理由
优点
- 关于名称对 ABI 是否重要存在混淆:xunion、结构体和协议看起来都很相似,但具有不同的规则。
缺点
不过,所有相关人员都认为,与 protobuf 相比,在结构体中引入序数会带来更大的混乱。
还有其他方法可以解决“此更改是否会更改 ABI”的问题,即:
- DIFL
- API 差异化,例如库的签名
名称对于文本格式(JSON、FIDLText 等)很重要,并且在这种情况下使用消息时,名称无法更改。
摘要
为了更好地传达重新排列和重命名字段对 ABI 的影响,我们提议进行语法更改,以引入结构体字段的序数,其语法规则与表的语法规则类似。
设计初衷
仅关注成员在各种声明中能否安全地重命名或重新排序,我们会出现语法差异,这些差异是自然演变的,不会传达可能更改对 ABI 的影响。
此外,由于当前的结构体声明语法,编译器很难在发生更改时提供帮助和指导。
我们来看一些示例,这些示例都很小且均匀:
struct Name { table Name { enum Name {
T abc; 1: T abc; ABC = 1;
U xyz; 2: U xyz; XYZ = 2;
}; }; };
protocol Name { xunion Name { bits Name {
Abc(T t); T abc; ABC = 1;
Xyz(U u); U xyz; XYZ = 2;
}; }; };
从 ABI 的角度来看,有一些观察结果:
- 重新排序:除了结构体之外,所有内容都可以重新排序,而不会产生任何影响。
- 重命名:
- 结构体、表、枚举和位可以重命名,而不会产生影响
- 协议和 xunion 的 ABI 将会受到重命名的影响。
(从源代码兼容性角度来看,大多数绑定在重新排序后将与源代码兼容,而在重命名后将不兼容。)
根据这些观察,我们提议为结构体声明引入序数。上述示例现在将如下所示:
struct Name {
1: T abc;
2: U xyz;
};
具体而言:
- 序数必须从 1 开始,序数空间中不得有空缺(如果最大的序数是 7,则必须包含 1、2、3、4、5、6、7)。请参阅下文中的理由。
- 任何两个字段都不能声明相同的序数。
- 字段序数决定了字段在结构体中的放置位置,而不是其语法位置。
- v1 中的 JSON IR 没有任何更改,序数是通过结构体声明中的成员顺序传达的。请参阅 v2 中对 JSON IR 的计划更改。
编译器指南
为了举例说明编译器可以通过建议的语法提供的指导,我们考虑了一些示例并比较了它们的处理方式。
移除字段(中间)
No Ordinals With Ordinals
---------------- -------------
struct Name { struct Name {
T abc; 1: T abc;
- U def; - 2: U def;
V ghi; 3: V ghi;
}; };
---------------- ---------------
Breaks ABI, no Breaks ABI,
compiler help compiler error
移除字段(结束)
No Ordinals With Ordinals
---------------- -------------
struct Name { struct Name {
T abc; 1: T abc;
U def; 2: U def;
- V ghi; - 3: V ghi;
}; };
---------------- ---------------
Breaks ABI, no Breaks ABI, no
compiler help compiler help
添加字段
No Ordinals With Ordinals
---------------- -------------
struct Name { struct Name {
T abc; 1: T abc;
+ U def; + 3: U def;
V ghi; 2: V ghi;
}; };
---------------- ---------------
Breaks ABI, no Breaks ABI, no
compiler help compiler error
重新排列字段
No Ordinals With Ordinals
---------------- -------------
struct Name { struct Name {
+ U def; + 2: U def;
T abc; 1: T abc;
- U def; - 2: U def;
V ghi; 3: V ghi;
}; };
---------------- ---------------
Breaks ABI, no Safe
compiler warning
禁止使用“预留”关键字
由于我们要使结构体的序数规则与表的序数规则保持一致,因此我们也可以考虑允许使用“reserved”关键字。
我们应该做的恰恰相反:正确解析意外使用预留关键字的情况,并提供清晰的编译器错误和说明。例如“Cannot reserve member in structs. 添加或移除成员会改变结构体布局,请改为考虑手动初始化中性成员。”
还有其他重要原因不允许使用“已预订”关键字:
- 与表不同,在结构体中引入内边距必须使用显式大小(即字节数);
- 在结构体中使用内存填充是为了非常具体的用途,例如当开发者需要特定的内存布局时。由于 FIDL 布局始终是 8 字节对齐的,因此这种用例很少见,甚至不存在。
- 在实现方面,我们在 RFC-0066:程序员建议明确默认值中阐明并解释了,对于某些绑定(例如 C、LLCPP),保证某些值被初始化的要求过于严格。因此,如果我们要在结构体中引入“预留”槽,则需要将其公开给后端,以便将其公开给开发者进行正确初始化。所有这些似乎都没有必要。
未来的 JSON IR
为了同时支持字段排序(按序数)和出于文档目的的排序(应遵循声明顺序),最好:
- 将声明顺序表示为“members”键中字段的显示顺序。
- 通过引入“序数”键来表示序数顺序。
设计
待定
实施策略
- 引入对新语法的支持,同时支持旧版语法;
- 将所有源文件迁移到新语法;
- 在使用旧版语法时添加警告,并给予一周的时间,以确保不再添加任何旧版语法的用法;
- 移除了对旧版语法的支持。
工效学设计
此提案通过语法向开发者传达 ABI 影响,从而改善了人体工学。请参阅下文中对此的反对意见。
文档和示例
至少:
向后兼容性
这不向后兼容源代码级别。如需进行软迁移,请参阅实现策略。
性能
无影响。
安全
无影响。
测试
在 fidlc
中进行单元测试,以验证以下内容:
- 解析;
- 序数从 1 开始,不得有空缺;
- JSON IR 没有任何变化。
缺点、替代方案和未知情况
替代方案:表的序数哈希
我们还考虑过对表使用序数哈希:语法更改将会舍弃显式序数,使结构体成为唯一使用此语法的声明(以前是协议和表)。
首先,为结构体提供显式序数的好处将保持不变。 开发者仍然可以按语法重新排列字段,并且更改序数会指示 ABI 破坏。
其次,我们不太可能根据探索结果从表格中移除序数,因为运行时开销(性能较低)与人体工学优势之间的权衡不利于后者。
缺点:结构体和表可能会混淆
随着结构体和表之间的语法趋于一致以及引入有序数,有些人可能会将结构体与表混淆,并错误地认为移除字段与 ABI 兼容。虽然移除结构体中间的字段会因序列中出现空隙而导致错误,但移除序列中序号最大的字段不会导致任何问题。
在先技术和参考文档
待定