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

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

为了更好地传达重新排序和重命名字段对 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. 添加或移除成员会改变结构体布局,请考虑改为手动初始化中性成员。

此外,还有一些重要原因允许使用“保留”关键字:

  1. 与表不同,在结构体中引入填充必须使用明确的大小(即字节数);
  2. 在结构体中使用填充是为了非常特定的目的,即当开发者需要特定的内存布局时。这种情况很少见,甚至不存在,因为 FIDL 布局始终是 8 字节对齐的。
  3. 在实现方面,我们在 RFC-0066:程序员建议 - 显式默认值中阐明并解释了,保证某些值被初始化对于某些绑定(例如 C、LLCPP)来说要求过高。因此,如果我们要在结构体中引入“预留”槽,就需要将其公开给后端,以便将其公开给开发者以进行适当的初始化。这一切似乎都是不必要的。

未来 JSON IR

为了同时支持按序号对字段进行排序和出于文档编制目的进行排序(应遵循声明顺序),最好:

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

设计

待定

实施策略

  1. 引入对新语法的支持,同时支持之前的语法;
  2. 将所有源文件迁移到新语法;
  3. 在使用旧语法时添加警告,并提供一周的时间来确保不会添加任何使用旧语法的新内容;
  4. 移除对之前语法的支持。

工效学设计

此提案通过语法向开发者传达 ABI 影响,从而改进人体工程学。请参阅下方的对此的反对观点

文档和示例

至少:

向后兼容性

这不属于源代码级向后兼容性。 如需了解如何进行软迁移,请参阅实现策略

性能

无影响。

安全

无影响。

测试

fidlc 中进行单元测试,以验证(包括但不限于):

  • 解析;
  • 序号从 1 开始,不得有间隔;
  • JSON IR 无变化。

缺点、替代方案和未知因素

替代方案:针对表的序数哈希

我们还考虑了对表使用序数哈希:语法更改将是删除显式序数,使结构成为唯一具有此语法的声明(而以前是在协议和表上)。

首先,拥有结构体的显式序号的好处将得以保留。 开发者仍然可以按语法重新排序字段,而更改序号会表明 ABI 发生中断。

其次,我们不太可能采取探索性措施来从表格中移除序数,因为运行时成本(性能降低)与人体工程学优势之间的权衡结果表明,前者超过了后者。

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

随着结构体和表之间的语法趋于一致,以及序数的引入,有些人可能会将结构体与表混淆,并错误地认为移除字段是 ABI 兼容的。 虽然移除结构体中间的字段会导致错误,因为序号序列中会出现缺口,但移除序号最大的字段则不会出现任何提示。

在先技术和参考资料

待定