RFC-0031:型型字符

RFC-0031:Typed Epitaphs
狀態已遭拒
區域
  • FIDL
說明

可指出墓誌銘類型的能力和語法。

Gerrit 變更
作者
提交日期 (年-月-日)2019-02-05
審查日期 (年-月-日)2021-04-07

拒絕原因

這項提案與服務探索的互動不佳,且實作複雜度估計偏高,因此遭到拒絕。

與服務探索互動

Fuchsia 上非常常見的模式是透過 fuchsia.io/Directory.Open 呼叫,依名稱要求特定通訊協定。這就是所謂的服務探索。 在服務探索期間,用戶端會與實作 fuchsia.io/Directory 通訊協定的伺服器互動。當該伺服器收到服務探索要求時,會找出適當的服務,並將管道的伺服器端轉移至所要求的服務。也就是說,用戶端會先與一個伺服器 (支援 fuchsia.io/Directory) 互動,然後再與另一個伺服器 (支援所要求的服務) 互動。

很抱歉,服務探索對墓誌銘設有嚴格限制。如果發生故障導致傳送墓誌銘,用戶端無法判斷是哪個對等互連發出墓誌銘,是支援 fuchsia.io/Directory 的伺服器,還是要求的服務?

實際上,服務探索可能包含的伺服器數量遠不只上述兩個。因此,墓誌銘必須非常籠統,不得包含特定領域的詳細資料。基本上,墓誌銘必須滿足所有可探索通訊協定的最小公分母,因此受到限制。

為解決這項限制,提案中討論了讓參與服務探索的所有通訊協定組成 fuchsia/IsDiscoverable 通訊協定。這個通訊協定會定義型別墓誌銘:


protocol IsDiscoverable {
    epitaph zx.status;
};

fuchsia/IsDiscoverable 的任何子項都無法定義自訂墓誌銘,因此可適當擷取型別系統中的限制。具體來說,這部分提案的內容如下:

通訊協定 (包括任何和所有組成的通訊協定,以遞迴方式) 的墓誌銘型別宣告不得超過一個。我們特別禁止兩個語意上等效的墓誌銘型別宣告使用相同型別。

不過,我們認為讓所有可探索的通訊協定組成這個新 fuchsia/IsDiscoverable 並不可行。舉例來說,由於服務探索是動態的,因此無法提供靜態強制執行。

與要求管道化互動

要求管道化模式可視為服務探索模式的概括,並對墓誌銘施加類似的嚴格限制。

導入複雜度

雖然 FIDL 功能相當複雜 (語言規則、JSON IR 擴充功能、繫結程式碼、產生的程式碼、人體工學),但型別墓誌銘的複雜度相當高,實用性卻很低。這項取捨並未讓我們欣喜若狂。

接下來該怎麼做?

本節代表作者的意見 (pascallouis@google.com)。

推出墓誌銘時的目標是「指出用戶端與伺服器連線關閉的原因」。

但 Epitaphs 未能達成這個目標,實用性也不高。 依賴墓誌銘的通訊協定也可以使用自訂事件,這類事件沒有上述任何缺點,也不會受到 FIDL 背後低階第一原則所造成的酬載限制

墓誌銘的優點之一是「乾淨終止」通訊協定,伺服器大多可確保用戶端對等互連會從管道取消繫結,並避免發出後續要求。

我們已提議導入適用於事件的 terminal 修飾符,以便改用自訂事件,同時保留「乾淨終止」屬性,不再使用墓誌銘。有了終端事件,程式庫作者就能隨意定義事件的酬載。為支援這項功能,我們會擴充線路格式,分配 transactional header 的一個旗標,指出通訊協定終止。收到標示為終端訊息的訊息時,除了正常處理外,用戶端也會終止連線。如果用戶端不知道事件 (在複雜的要求管道化案例中很可能發生),用戶端可能會瞭解交易標頭,但捨棄酬載。

摘要

我們建議:

  1. 新語法,用於指出通訊協定上墓誌銘的類型 (我們不會變更墓誌銘的預設類型 zx.status);
  2. 向繫結公開墓誌銘類型,以便在程式碼產生期間適當運用這項資訊;
  3. 補充組合模型,指定每個通訊協定都有專屬的墓誌銘類型,且會透過組合延續

我們預期會使用墓誌銘型別:在「葉片」通訊協定上 (即自行定義或組合其他通訊協定的通訊協定),或在「組合樹狀結構」中一次,並將墓誌銘型別放在「頂端」或「根」通訊協定上。

提振精神

重點摘要:我們喜歡型別,型別很棒,讓我們加入更多型別。

語法和錯誤類型

RFC-0053:墓誌銘中,我們介紹了墓誌銘的概念,也就是「一種機制,可讓伺服器在關閉連線前傳送訊息,說明連線關閉的原因」。墓誌銘包含錯誤狀態,目前已修正為 int32。在審查墓誌銘時,我們選擇將型別修正為 int32,以與 zx.status 重疊,並打算在日後將「使用者錯誤」與「通訊協定錯誤」合併。

RFC-0060:錯誤處理中,我們介紹了專門用於輸入錯誤的語法,特別指出「錯誤類型必須是 int32、uint32 或其中一種型別的列舉」。我們希望允許輸入墓誌銘的錯誤,並選擇與錯誤處理相符的表示法。

RFC-023:通訊協定的組合模型中,我們導入了宣告通訊協定和組合通訊協定的新語法。我們在此建議的墓誌銘語法也遵循這種風格。

我們認為這些先前的決定與提案 (1) 和 (2) 的方向一致。

附有墓誌銘的組合模型

命題 (3) 有兩個層面:每個通訊協定的墓誌銘類型獨一無二,以及組合下的行為。

墓誌銘的語意與特殊事件類似,因此每個通訊協定的回應類型都會不同。

組合下的行為遵循類似的思維,確認墓誌銘類型會組成。下文將討論替代定義及其缺點。

允許墓誌銘類型組合可能會導致遠距情境中出現潛在的斷裂。假設通訊協定 ChildWithEpitaph 包含通訊協定 FarawayParent,並將其墓誌銘類型定義為 SomeSpecificErrorCode 列舉。如果 FarawayParent 事後決定指定墓誌銘類型,系統就會禁止組合,且 ChildWithEpitaph 的編譯作業會失敗。

替代方案:墓誌銘不會撰寫

另一種做法是考慮只有定義的訊息 (方法和事件) 可以組成其他通訊協定。在這個替代模型中,如果父項通訊協定定義了墓誌銘型別,這個型別會獨立於子項通訊協定的墓誌銘型別 (可能不同)。舉例來說,我們會允許下列定義:

protocol Parent {
    epitaph ParentErrorCode;
};

protocol Child {
    compose Parent;
    epitaph ChildErrorCode;
};

由於我們未提供任何通訊協定之間的關係 (例如沒有 subsumption、沒有可演化規則),因此替代模型具有一些優點。如果同時使用墓誌銘輸入和撰寫功能,這項功能可提供更多自由。

不過,我們近期內會定義通訊協定之間的關係,因此應根據這項設計目標來評估這項選擇。舉例來說,如果我們導入正式的 subsumption 關係 (「是」),且某個通訊協定組成另一個通訊協定,但兩者定義的墓誌銘類型不相容,這些通訊協定會立即無法通過提交測試:預期某種墓誌銘類型的用戶端,無法處理其他墓誌銘類型。

因此,我們認為現在限制墓誌銘類型的使用方式是較好的選擇,這樣未來才能擴充。

設計

語法

我們擴充文法,允許在通訊協定宣告中加入 epitaph 節:


protocol SomeProtocol {
    ExampleMethod(...) -> (...);

    epitaph SomeErrorCode;
};

墓誌銘段落的語法與 compose 段落類似,且也遵循為錯誤規格選擇的語法。

正式來說,文法修改如下:

protocol-declaration = ( attribute-list ) , "protocol" , IDENTIFIER ,
                        "{" , ( protocol-member , ";" )*  , "}" ;

protocol-member = ...
                | "epitaph" type-constructor ; [NOTE]

NOTE: The epitaph stanza allows the more liberal type-constructor in the
grammar, but the compiler limits this to int32, uint32, or enum thereof. There
may be only one epitaph stanza per protocol definition.

ABI 和來源相容性

我們推出墓誌銘時,將類型修正為 int32,並預期會將其限制為 32 位元。導入錯誤語法時,也確認了將錯誤代碼修正為 32 位元。

在此,我們維持這項選擇,並如前所述,將墓誌銘型別限制為 int32、uint32 或其列舉。

因此,變更墓誌銘類型 (可能是從預設類型改為指定類型) 不會修改 ABI 相容性。

不過,變更墓誌銘類型很可能會造成來源層級的重大變更。繫結作者「可能」會破壞來源相容性。由於墓誌銘現在並不常見,我們預期這不會造成問題。

JSON IR

我們在 definition/interface 物件中新增 definitions/type 類型的成員 epitaph。

例如:

    {
      "name": "example/SomeProtocol",
      "epitaph": {
          "kind": "primitive",
          "subtype": "uint32"
      },
      "methods": [
        {
          "ordinal": 296942602,

墓誌銘型別一律會出現在介面宣告中,且如果未另行指定,則會設為預設的 zx.status

撰寫墓誌銘

將通訊協定組合到另一個通訊協定時,墓誌銘的型別會沿用。 舉例來說,使用以下通訊協定:

protocol Parent {
    epitaph SomeErrorCode;
};

protocol Child {
    compose Parent;
};

ParentChild 的結果墓誌銘類型都是 SomeErrorCode

通訊協定 (包括任何和所有組合通訊協定,以遞迴方式) 的墓誌銘類型宣告不得超過一個。具體來說,我們禁止兩個語意等價的墓誌銘型別宣告使用相同型別。

這個範例無效,應該無法編譯:

protocol Parent1 {
    epitaph SomeErrorCode1;
};

protocol Parent2 {
    epitaph SomeErrorCode2;
};

protocol Child {
    compose Parent1;
    compose Parent2;
};

這個範例也無效,應該無法編譯:

protocol Parent {
    epitaph SomeErrorCode;
};

protocol Child {
    compose Parent;
    epitaph SomeErrorCode;
};

導入策略

(由 FIDL 團隊審查後決定。這項異動與先前的許多異動類似。)

人體工學

不適用

說明文件和範例

須符合以下條件:

  • 線路格式規格應指出墓誌銘為 int32/uint32,需要以適當的型別解讀。
  • 應使用「ZX_OK (或相關成功代碼)」等陳述,釐清開發人員指南,將建議擴大至開發人員指定的類型。

回溯相容性

FIDL 來源:由於我們擴充了語言文法,因此嚴格來說可回溯相容。在這項變更之前,任何 FIDL 檔案都無法在通訊協定宣告中包含「epitaph type-constructor;」節。

JSON IR:向後相容於允許額外鍵的非嚴格剖析器,因為我們會在所有介面宣告中新增「墓誌銘」鍵。

效能

不會影響效能。

安全性

沒有影響,或因額外的型別安全而略有正面影響。

測試

fidlc 中的單元測試,以及繫結生成測試。

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

不適用

先前技術和參考資料

(如內文所述)。