RFC-0036:结构体声明的更新

RFC-0036:对结构体声明的更新
状态已拒绝
领域
  • FIDL
说明

为了更好地传达对字段重新排序和重命名字段对 ABI 的影响,我们提议进行一项语法更改,为结构体字段引入序数,其语法规则与表的语法规则类似。

作者
  • pascallouis@google.com
提交日期(年-月-日)2019-03-07
审核日期(年-月-日)2019-03-14

遭拒的理由

优点

  • 混淆名称对 ABI 是否很重要或不存在:xunion、struct 和协议都看起来相似,但规则不同。

缺点

  • 不过,大家都认为在结构体上引入序数的混淆效果远远超过了该标准,尤其是与 protobuf 相比。

  • 还有一些其他方法可以解决“是否更改 ABI”问题,即:

    • 迪士尼航空
    • 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

禁用“预留”关键字

由于我们要在表的表中对齐结构体的序数规则,因此我们可以设法允许“预留”关键字。

我们应该执行完全相反的操作:正确解析预留关键字的意外使用,并提供明确的编译器错误和解释。例如“无法在结构体中保留成员。添加或移除成员会改变结构体布局,请考虑手动初始化中性成员。”

此外,还有其他一些重要原因不得允许使用“已预留”的关键字:

  1. 与表不同,在结构体中引入内边距时,必须明确指定大小(即字节数);
  2. 当开发者需要特定的内存布局时,在结构体中使用内边距是出于非常具体的目的。这种用例很少见,甚至不存在,因为 FIDL 布局始终是 8 字节对齐。
  3. 在实现方面,我们已在 RFC-0066:编程人员公告显式默认值 (RFC-0066)因此,如果我们在结构体中引入“预留”槽,则需要将其公开给后端,以便向开发者公开,以进行正确的初始化。这一切似乎都没有必要。

公路 JSON IR

为了同时支持字段排序(按序数)和出于文档目的排序(应遵守声明顺序),最好执行以下操作:

  • 将声明顺序表示为字段在“members”键中的显示顺序。
  • 通过引入“序数”键表示序数顺序。

设计

待定

实施策略

  1. 引入对新语法的支持,同时支持旧语法;
  2. 将所有源文件迁移到新语法;
  3. 在使用旧语法时添加警告,并留出一周时间,确保没有新增使用先前语法的新用法;
  4. 取消对旧语法的支持。

工效学设计

此方案通过语法向开发者传达 ABI 影响,从而改善工效学设计。请参阅下文中与此相反的观点

文档和示例

至少:

向后兼容性

这不可向后兼容。请参阅实现策略进行软迁移。

性能

无影响。

安全性

无影响。

测试

fidlc 中的单元测试,用于验证其他项目:

  • 解析;
  • 序数从 1 开始,不能有间隙;
  • 对 JSON IR 没有变化。

缺点、替代方案和未知情况

替代方案:对表进行序数哈希处理

我们还考虑对表使用序数哈希处理:语法变化将丢弃显式序数,使结构体成为唯一使用此语法的声明(而以前适用于协议和表)。

首先,为结构体提供显式序数的优势仍将保持不变。开发者仍然可以对字段进行语法重新排序,更改序数表示破坏 ABI 合规性。

其次,我们不太可能根据探索采取行动,从表中移除序数,因为运行时间成本(性能降低)之间的权衡大于工效学效益。

缺点:结构体和表可能会混淆

由于结构体和表之间的语法趋于融合,并且引入了序数,一些人可能会将结构体与表混淆,并错误地认为移除字段与 ABI 兼容。虽然移除结构体中间的字段会导致错误,因为序数序列中存在缺口,但移除具有最大序数的字段则是无声的。

早期技术和参考资料

待定