RFC-0044:可擴充方法引數

RFC-0044:可擴充的方法引數
狀態已遭拒
區域
  • FIDL
說明

我們建議 FIDL 程式庫作者在需要可擴充性時使用資料表,而非結構體,但方法引數會編碼為結構體。這項提案提出了一種方法,可在表格上建立可擴充的方法引數。

作者
提交日期 (年-月-日)2019-04-08

拒絕理由

已由 RFC-0050:語法重整取代。

摘要

我們建議 FIDL 程式庫作者在需要可擴充性時使用資料表,而非結構體,但方法引數會編碼為結構體。這項提案提出了一種方法,可讓可擴充的方法引數建構在資料表之上。

提振精神

由於可擴充方法引數缺乏語法,因此程式庫作者不太可能使用表格來讓方法引數可擴充。將這項資訊納入語法後,設計通訊協定時就能將可擴充性納入考量。

模組團隊正在設計協定,這些協定必須同時維持 ABI 相容性,並在發現新需求及改進設計時可延伸。他們正在考慮以表格定義方法,並在離線狀態下宣告這些表格。

設計

此提案會擴充 FIDL 原始語言,並影響語言繫結。

FIDL 語法

它針對方法和事件要求和回應引數的語法提出擴充功能,以便在引數結構中新增資料表。

例如以下這個通訊協定:

protocol Example {
    Foo(int32 arg1, { 1: string arg2, 2: bool arg3 }) -> ({});
};

宣告方法,其中包含一個必要引數、兩個選用引數、可擴充的要求和可擴充的回應。這相當於宣告:

table ExampleFooRequestExtension {
    1: string arg2;
    2: bool arg3;
};
table ExampleFooResponseExtension {
};
protocol Example {
    Foo(int32 arg1, ExampleFooRequestExtension extension)
        -> (ExampleFooResponseExtension extension);
}

IR

目前的 IR 版本可透過回溯相容的方式擴充。可擴充的資料表方法引數包含以下名稱:{Protocol}{Method}RequestExtension{Protocol}{Method}ResponseExtension{Protocol}{Method}EventExtension。系統會在這些產生的資料表上設定 [ExtensionArgument] 屬性,以便繫結產生器在需要時特別處理這些屬性。

未來的 IR 可能會將這個概念提升至更優質的結構。未來的 IR 應允許更靈活的宣告命名方式,以便語言在命名擴充資料表時做出更好的選擇,例如 C++ 可以在通訊協定定義類別中巢狀這些資料表。

繫結

繫結不需要針對可擴充方法引數提供特殊支援。現有的繫結產生器只會將產生的資料表納入方法的最後一個引數。

C++

舉例來說,如果不對上述通訊協定進行任何變更,C++ 繫結大致會如下所示:

class ExampleFooRequestExtension;
class ExampleFooResponseExtension;
class Example {
  using FooCallback = fit::function<void(ExampleFooResponseExtension)>;
  virtual void Foo(int32_t arg1,
                   ExampleFooRequestExtension extension,
                   FooCallback callback) = 0;
};

您也可以透過以下方法繫結此通訊協定:

class Example {
  using FooCallback = fit::function<void()>;
  virtual void Foo(int32_t arg1,
                   FooCallback callback,
                   std::optional<std::string> arg2 = std::optional<std::string>(),
                   std::optional<bool> arg3 = std::optional<bool>()) = 0;
};

這會更貼近方法的宣告方式,但會將回呼引數置於靜態和可擴充引數之間。

Dart

Dart 支援選用的命名引數,可將 FIDL 概念與其語法進行完美對應。Dart 不支援元組或可變參數的未來值,這仍是限制。繫結介面可能會如下所示:

abstract class Example {
  Future<ExampleFooResponseExtension> foo(int arg1, {String arg2, bool arg3});
}

使用這個語法新增其他擴充引數,可保留來源相容性。

荒漠油廠

未定

查看

未定

簡易 C

簡單的 C 繫結不支援資料表,因此這項功能與這些繫結不相容。

導入策略

第一步是將新語法支援功能新增至 fidlc,並更新參考資料和教學課程說明文件。

接下來,我們會為 Dart 繫結新增支援功能,因為這類繫結最能帶來明顯的人體工學效益。

人體工學

允許 FIDL 通訊協定演進是使用者所需的重要功能。目前變更方法的引數會造成 ABI 和 API 的破壞性變更。軟化方法的做法是為每個變更引進新的類別名稱,並在仍有呼叫端的情況下繼續支援舊方法,或是將資料表納入引數,並在該資料表中新增引數。這項提案可讓您以更符合人體工學的方式表達後一種方法。它會保留方法定義中定義的引數,方便在說明文件註解中參照。

許多程式設計語言都會使用可選的引數。這對程式庫作者來說並非新概念。

資料表需要明確的序數,因此擴充引數與必要引數不一致,但最好還是讓兩者保持一致,不要引入使用雜湊序數的新表格式結構。

說明文件和範例

作為 FIDL 語言的擴充功能,應更新 FIDL 參考資料和教學課程文件。

回溯相容性

現有的 FIDL 程式庫不會受到這項異動影響。

這項提案大幅提升了程式庫作者長期維護 ABI 相容介面的效能。

原始碼相容性的限制仍未確定,我們會根據綁定支援語言的方式提供相關資訊。

成效

相較於結構體,編碼和解碼表格所需的成本較高,因此效能至關重要的通訊協定應盡量少用這項功能

安全性

沒有影響

測試

測試應新增至 fidlc。危險 ID 測試應測試危險 ID 是否用於選用引數。

缺點、替代方案和未知事項

替代方案

我們可以根據個別方法或個別通訊協定,從結構體切換至資料表。我們甚至可以將預設值從結構體切換為資料表。這種做法較不靈活。通常只會延長要求或回應。通常,部分引數 (例如 Modular 中的模組 ID) 預期會長期保持穩定,其他則不會。

我們可以定義類似表格的資料結構,讓系統為每個擴充引數產生哈希值,以便計算序數,而無需使用表格和為每個擴充引數要求序數。這會簡化原始語言的語法,但會增加編碼器、解碼器和語言繫結的複雜度。

我們可以使用版本化方法。我們並未深入探討這個選項。

開放式問題

我們應決定如何在 C++、Rust 和 Go 中綁定此項目。

是否應允許新增引數破壞來源相容性?

既有技術與參考資料

Protobuf 會在通訊協定方法之外宣告訊息。

Flatbuffers 和 cap'n proto 會使用版本。