RFC-0031:已輸入的墓誌銘文 | |
---|---|
狀態 | 已遭拒 |
區域 |
|
說明 | 用來表示墓誌銘文類型的功能和語法。 |
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) 的意見。
推出碑文時,所述目標是「提供指示,說明為何關閉用戶端至伺服器連線」。
墓誌銘文並未達到這個目標,實用性也相當有限。依賴碑文的通訊協定也可以使用自訂事件,這類事件不存在上述缺點,也不受 FIDL 背後低階第一原則所強加的酬載限制。
紀念碑的其中一個優點是可讓通訊協定「乾淨終止」,在這種情況下,伺服器幾乎可確保用戶端同端會從管道解除繫結,並避免發出後續要求。
我們已提出引入可套用於事件的 terminal
修飾符的想法,以便轉移使用碑銘,並將自訂事件轉移至不失去「清除結束」屬性的情況。使用終端事件時,程式庫作者可以自由定義事件的酬載。為支援這項功能,我們會擴充線路格式,分配一個 交易標頭旗標,用來指出通訊協定的終止。收到標示為終端的訊息後,除了正常處理外,用戶端也會終止連線。如果用戶端不瞭解事件 (在複雜的要求管線處理情況下很可能發生),用戶端可以瞭解交易標頭,但酬載則會遭到捨棄。
摘要
我們建議:
- 新的語法,用於在通訊協定中指出銘文的類型 (我們不會變更銘文的預設類型
zx.status
)。 - 一種將銘文類型公開至繫結的方式,以便在產生程式碼期間適當運用這項資訊。
- 補充組合模型,指定銘文的類型為每個通訊協定專屬,且由組合帶入。
我們預期會在以下情況使用墓誌銘文型別:在「葉」通訊協定 (即由自身定義或組合其他通訊協定) 中使用,或在「組合樹狀結構」中使用,並將墓誌銘文型別放在「頂層」或「根」通訊協定中。
提振精神
重點摘要:我們喜歡類型,類型很棒,讓我們多使用類型。
語法和錯誤類型
在 RFC-0053:Epitaphs 中,我們介紹了 Epitaph 的概念,這是一種機制,可讓伺服器在關閉連線前傳送訊息,指出為何要關閉連線。碑文包含錯誤狀態,目前已修正為 int32。在審查碑文時,我們選擇將類型修正為 int32,以便與 zx.status 重疊,並且日後將「使用者錯誤」與「通訊協定錯誤」合併。
在 RFC-0060:錯誤處理中,我們引入了語法,用於處理特定類型的錯誤,特別指出「錯誤類型必須是 int32、uint32,或其中一個類型的枚舉」。我們希望允許輸入碑文錯誤,並選擇與錯誤處理相符的表示法。
在 RFC-023:通訊協定的組合模型中,我們引入了新的語法,用於宣告通訊協定和組合通訊協定。我們在此處提出的墓誌銘語語法就遵循這項風格。
我們認為所有先前決策的方向都與 (1) 和 (2) 命題一致。
含有碑文的組合模型
命題 (3) 有兩個層面,分別是每個通訊協定中 epitaph 類型的獨特性,以及組合下的行為。
銘文的語意與特殊事件的語意相似,因此回應類型會依通訊協定而異。
組合下的行為會遵循類似的思維方式,確認碑文的類型會組合。我們將在下文討論另一種定義,以及這種定義的缺點。
允許 Epitaph 類型進行組合,會在遠端情境中引入潛在的損壞情形。請考慮一個通訊協定 ChildWithEpitaph
如何組合通訊協定 FarawayParent
,並將其墓誌銘類型定義為 SomeSpecificErrorCode
列舉。如果 FarawayParent
事後決定指定墓誌銘類型,則系統會禁止組合,並且 ChildWithEpitaph
的編譯作業會失敗。
替代做法:不要使用 Epitaphs 進行組合
另一種做法是考量只有定義的訊息 (方法和事件) 才能組合成另一個通訊協定。在這個替代模型中,如果父項通訊協定定義了碑文類型,這個類型就會與子項通訊協定的可能獨立碑文類型無關。舉例來說,我們會允許下列定義:
protocol Parent {
epitaph ParentErrorCode;
};
protocol Child {
compose Parent;
epitaph ChildErrorCode;
};
由於我們不會在通訊協定之間提供任何關係 (例如沒有包含子類、沒有可進化規則),因此替代模型具有一些優點。在使用碑文類型和組合時,這項功能可提供更大的自由度。
不過,我們有意在近期內定義協定之間的關係,因此應根據此設計目標權衡這項選擇。舉例來說,如果我們引入正式的從屬關係 (「is a」),當某個通訊協定組合另一個通訊協定時,如果兩者都定義不相容的墓誌銘類型,這些通訊協定會立即失敗提交測試:預期某種墓誌銘類型的用戶端將無法處理另一種墓誌銘類型。
因此,我們認為在今天限制墓誌銘類型的使用方式,是較好的選擇,這樣日後才有擴充功能可用。
設計
語法
我們擴充文法,允許在通訊協定宣告中使用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 位元。
我們會保留這個選項,並如前所述,將 epitaph 類型限制為 int32、uint32 或相關列舉。
因此,變更碑文類型 (例如從預設變更為指定的類型) 不會修改 ABI 相容性。
不過,變更碑文類型很可能會造成來源層級的重大變更。綁定作者可能會破壞原始碼相容性。我們不認為這會造成問題,因為墓誌銘文在現今已不常使用。
JSON IR
我們會在 definition/interface
物件中加入 definitions/type
類型的成員墓誌銘。
舉例來說,我們可能會:
{
"name": "example/SomeProtocol",
"epitaph": {
"kind": "primitive",
"subtype": "uint32"
},
"methods": [
{
"ordinal": 296942602,
銘文類型一律會出現在介面宣告中,如果未指定其他值,則會設為預設的 zx.status
。
撰寫墓誌銘文
將一組通訊協定轉換為另一組時,銘文的類型會保留。例如,使用以下通訊協定:
protocol Parent {
epitaph SomeErrorCode;
};
protocol Child {
compose Parent;
};
Parent
和 Child
產生的墓誌銘類型為 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 團隊在審查後決定。這項異動與許多先前的異動並無二致。)
人體工學
無
說明文件和範例
至少:
回溯相容性
FIDL 來源:由於我們正在擴充語言文法,因此嚴格遵循回溯相容性。在變更之前,任何 FIDL 檔案都無法在通訊協定宣告中加入「epitaph type-constructor」節。
JSON IR:針對允許額外鍵的非嚴格解析器,提供向後相容性,因為我們會將「epitaph」鍵新增至所有介面宣告。
成效
不會影響效能。
安全性
不會造成影響,或是在提供額外類型安全性的情況下,帶來些許正面影響。
測試
在 fidlc 中進行單元測試,以及繫結產生測試。
缺點、替代方案和未知事項
無
既有技術與參考資料
(如文中所述)。