RFC-0023:通訊協定的組合模型 | |
---|---|
狀態 | 已接受 |
領域 |
|
說明 | 關鍵字介面由關鍵字通訊協定取代。擴充通訊協定明確表示一個組成模型,將一個通訊協定定義為一組訊息,並由一或多個其他通訊協定進行擴增。通訊協定擴充功能的語法已從繼承的語法變更為類似混合的語法。 |
作者 | |
提交日期 (年-月-日) | 2018-12-10 |
審查日期 (年-月-日) | 2019-01-09 |
摘要
我們建議進行下列變更:
- 關鍵字「介面」已由關鍵字「通訊協定」取代。 (本文件的其他部分將使用「通訊協定」一詞)。
- 清楚說明延伸通訊協定,用於表示「組合模型」,其中之一 是一組訊息,以一或多個其他通訊協定來擴增。
- 通訊協定擴充功能使用的語法已從類似「繼承」的語法變更 與 mixins 類似。
- 繫結作者必須避免提出子假設 (例如「is-a」階層、繼承、替換) 代表以目標語言編寫的通訊協定。
提振精神
「介面」一詞附帶的情境行李則如方法所示: 超載、建構函式和解構、訊息接收者的物件模型等等。
然而,FIDL 的目標較為簡單,用於描述兩者之間的通訊協定 兩個對等互連,也就是可以交換一組訊息。
我們會明確指出要啟動 FIDL API, 雖然語法類似物件導向介面的定義, 比物件系統更類似於網路通訊協定。」 有機會導入更「以物件為導向」的選項時功能 這點我們沒想到這點 (例如最近收到了關於 RFC-0020:序數雜湊)。
我們希望在用語中更清楚地說明這個差異,因此建議您調整
方法是將關鍵字 interface
取代為關鍵字 protocol
。
此外,「is-a」如果借用繼承語法所隱含的關係是無錯的, 導致使用者的期待不正確 (為求明確,FIDL 不提供這類繼承語意,但語法會盡量建議這麼做)。 請參閱「Is A」人際關係可能有害 一節。
設計
本提案介紹了正式語意,說明程序互動情形和通訊協定。
本提案變更了 FIDL 來源語言,以闡明通訊協定擴充功能的語意。 並提供有關繫結作者的新指南。
目前,繼承關係未在 JSON IR 中顯示,因此無法 如為繫結作者使用。 因此,我們預期這個新指引的調整方式,不會有任何變動 繫結程式碼,但除了改良過的說明文件之外。
本提案不會變更電匯格式。
本提案不會變更 JSON IR,但預計會加入一個鍵重新命名 未來還會進行大幅變更
通訊協定模型
Zircon 管道不需要特定結構定義,即可進行其傳輸的酬載。 FIDL 以此基元為基礎,並限制管道必須使用特定通訊協定。 如此一來,FIDL 會在管道結尾處加上意義和名稱。 我們分別命名為「用戶端」和另一個「伺服器」。
我們的模型會將通訊協定描述為一組直接互動。 搭配選用的 epitaph。 我們稱之為用戶端之間通訊的特定工作階段。 並透過通訊協定連線至伺服器
方向可以是「用戶端到伺服器」或「從伺服器到用戶端」。
互動開頭為請求,可選擇回應。 我們常常使用「射後不理」一詞或「單向」用於無回應互動 以及「call」一詞預測要求回應
要求和回應都是「訊息」,以標頭表示。 然後是結構體的承載,也就是結構體的引數 要求或回應
目前,我們限制伺服器對用戶端訊息的回應, 簡單地說「事件只是起火而漏掉」。
Peitaph 是指完成工作階段的伺服器對用戶端互動。 詳情請參閱 RFC-0053: Epitaphs 網站。
這個模型中缺少事件,屬於更複雜的互動,例如三向握手。 TCP 的 SYN/SYN-ACK/ACK。 我們認為這是超出範圍的情況,因此日後模型的修正也不太可能涵蓋在內。
組合模型
如今,通訊協定可以定義互動,也可以擴充一或多個通訊協定。 產生的通訊協定 (「撰寫的通訊協定」) 會包含所有直接定義的互動, 以及繼承由慣例定義的所有互動 (直接或間接)。
舉例來說,Child
通訊協定的定義為:
protocol Parent1 { Method1(); };
protocol Parent2 { Method2(); };
protocol Child { compose Parent1; compose Parent 2; Method3(); };
具有以下三種互動:Method1
、Method2
和 Method3
。
不過,無論 Method1
和 Method2
是否因組合而在 Child
中定義,
也不會直接用於語言專屬的後端
在 JSON IR 中。
「是 A」經認定為有害的關係
因為通訊協定可以同時處理雙向要求,因此具有副作用的關係 更要小心 因此,我們不允許通訊協定將「是」關係 擴充的通訊協定
例如,假設我們有兩個通訊協定:
protocol Parent { Method(); };
protocol Child { ->Event(...); };
我們允許含有通訊協定 Child
的管道,以Parent
的形式呈現
(亦即「Child
與 Parent
」的關係),我們會公開用戶端接收 Event
、
這個 API 就是我們無法處理的問題
如需具體範例,請參閱下一節。
我們會改為支援特定的通訊協定註解,例如「僅限用戶端」 到伺服器互動」支援,且允許「為」關係 發生這種情況時,這類關係會牽動到 JSON IR 以使用後端。
仰賴「是 A」現況
透過具體範例,fuchsia.media 程式庫包含多個通訊協定。 請特別注意以下幾點:
AudioCapturer 或 AudioRenderer 都未定義事件,意即這些事件只是純粹。 用戶端對伺服器通訊協定— 皆為單向式。 (StreamSource 定義了兩個事件,但以下將明確說明 通訊協定本身的定義)
因此,如果用戶端知道如何與 StreamBufferSet 或 StreamSource 互動 (分別為 StreamBufferSet 或 StreamSink),則可與 AudioCapturer (和 AudioRenderer) - 即用戶端只需 忽略公開的額外方法 在清單中,我們可以定義「是」產生關聯
不過,如果事件新增至任一介面,則「是」 也會停止。 假設用戶端與 StreamBufferSet 互動, 伺服器端的 AudioRenderer。 如果 AudioRenderer 觸發事件,會發生什麼情況? 用戶端會如何處理這個情況?
由於我們 (尚無法) 在 fidlc
中提供這項區別,
我們要確認「不是」系統支援關係。
本提案基本上闡述了現狀。
就像 fuchsia.media 案例所示,已知具有特定關係的作者 可以根據自己的需求建立繫結 (使用投放等)。
在後續提案中,我們預計會導入屬性或新關鍵字,以擷取 基於此方向限制,並提供「is a」物件關係 在提案之前,我們無法為 FIDL 工具鍊提供更完善的支援。
語法變更
在設計階段,我們提出了幾種不同的替代方案 請參閱下方的缺點、替代方案與不明
使用可接受語法的擴充通訊協定,如下所示:
protocol Parent1 {
Method1OfParent1();
Method2OfParent1();
};
protocol Parent2 {
Method1OfParent2();
Method2OfParent2();
};
protocol Child {
compose Parent1;
compose Parent2;
Method1OfChild();
Method2OfChild();
};
文法上的正式變更如下:
declaration = const-declaration | enum-declaration | protocol-declaration |
struct-declaration | union-declaration | table-declaration ;
protocol-declaration = ( attribute-list ) , "protocol" , IDENTIFIER ,
"{" , ( method-or-compose-declaration , ";" )* , "}";
method-or-compose = method-declaration | compose-declaration ;
method-declaration = ( ordinal , ":" ) , method-parameters ;
method-parameters = IDENTIFIER , parameter-list , ( "->" , parameter-list )
| "->" , IDENTIFIER , parameter-list ;
compose-declaration = "compose", compound-identifier ;
組成的通訊協定只能提及一次。
可能的擴充功能
我們預計在後續提案中另外允許伺服器對用戶端 因此需要回應,進而啟用多工通訊協定 也可能會以反向順序管道舉例來說,執行個體 coordinator.fidl 定義 兩個指令回應的通訊協定,一個從 devmgr -> 存取還有 devhost 和 devhost 相比 ->devmgr。目前這些是手動混合,須仰賴序數 也就是這樣
我們可能會使用「->」語法稍後會反向引入多工處理。 替代方法是只在擴充功能包含 因此反向通訊協定不需要導入任何方向語法 因為我們在移除時採用反向通訊協定。
我們允許將 Compose 區塊放在 通訊協定、 我們也允許使用多個 Compose 區塊 或者,我們也可以只有一個區塊,加在頂端。 因此,我們選擇對外開放,並採用自動格式和/或樣式指南 而不是將違規處置加進語言本身
JSON IR
本次異動不會變更 JSON IR。
而是將「interface_declarations」重新命名為金鑰設為「protocol_declarations」 進行大量變更 這類重大變更必須採取多步驟做法,將結構定義版本的 0.0.1 至 0.0.2,並提供後端調整的過渡期。
遠處發生服務中斷情形,使用 [FragileBase]
這個提案不會改變距離可能中斷的可能性
因此,我們再次確認 [FragileBase]
是否用於擴充任何通訊協定1。
繫結作者指南
- 繫結必須避免子假設 (例如「is-a」階層、繼承、子類別) 代表以目標語言編寫的通訊協定。
- 這應為錯誤接收未知序數的錯誤。 繫結應以「不明序數錯誤」表示,然後關閉管道。
執行策略
三個步驟:
- 新增對新語法的支援;
- 轉換所有 FIDL 檔案以使用新的語法;
- 停止支援舊語法。
人體工學
這項變更讓 FIDL 更加清楚易懂,請參閱動機一節。 這項變更或許能讓事先瞭解 FIDL 並不容易,但可避免 他們對路途產生誤解,因而產生與期望不符的期望。
說明文件和範例
我們需要更新語言、文法、評分量表和其他相關說明文件。
回溯相容性
這項變更會破壞與目前使用繼承設定的 FIDL 檔案來源相容性。 如導入中所述,我們將分階段採取分階段的做法, 引入新語法,遷移所有 FIDL 檔案,然後停止支援舊語法。
這項變更不會變更 FIDL 線格式,因此屬於回溯相容的 ABI 變更。
成效
不影響效能。
安全性
我們或許能運用更緊密的輸入語意來保護頻道,或是觀察頻道。 這並非本提案的目標,不僅無法顛覆現狀,而且可以改進。
測試
您可以完全在 fidlc
層級使用單元測試來測試這項變更。
缺點、替代方案和未知
以下各節記錄設計階段提出的替代語法。
替代語法 (pascallouis@)
範例:
protocol Parent1 { Method1(); };
protocol Parent2 { Method2(); };
protocol Child {
compose {
-> Parent1();
-> Parent2();
};
Method1OfChild();
}
注意:這是原先提議的語法。
出現 compose
區塊看起來不自然,導致語言偏離現有的語言,
建議將多個通訊協定組合成多個通訊協定,而只組合單一
感覺詳細
此外,我們還不清楚是否允許多個 compose
區塊,以及這樣如何
程式碼看起來會像這樣
最後,我們選擇改回顯示方向「->
」通訊協定偏好指標
利用多方向混合辦公 (如果這類特徵
才會列入考量)。
替代語法 (jeremymanson@)
原因:為明確指出我們預期應導入和 一系列定義通訊協定的方法:
範例:
protocol Parent1 {
Method1OfParent1();
Method2OfParent1();
};
protocol Parent2 {
Method1OfParent2();
Method2OfParent2();
};
interface Child {
compose {
-> Parent1();
-> Parent2();
};
Method1OfChild();
};
注意:「介面」關鍵字代表每個方法都必須有實作程序
和「通訊協定」關鍵字代表符合通訊協定和介面的規定
曾經有經驗
我們不一定預期 StreamSource
有自己的實作內容。
我們能進一步指出不會有任何變化,因此不再沿用導入作業。
無法組合介面至其他介面。
替代語法:類似 Go 的介面組合 (proppy@)
原因:看起來不像繼承,而是對介面的 Golang 語法不熟悉 嵌入
範例:
protocol Parent1 { Method1(); };
protocol Parent2 { Method2(); };
protocol Child {
Parent1;
Parent2;
Method3();
};
注意:Go 語言規格 介面和嵌入功能
替代語法:使用宣告 (jeffbrown@)
原因:不像沿用機制,而是重複使用現有關鍵字來指定名稱 我們考慮的重點 較不可能與方法宣告或「屬性」2 混淆。
範例:
protocol Parent1 { Method1(); };
protocol Parent2 { Method2(); };
protocol Child {
using Parent1;
using Parent2;
Method3();
};
注意:FIDL、C++、Rust 和其他語言中的前例。
替代關鍵字
「compose
」的替代方案關鍵字:
extends
(pascallouis@)contains
(smklein@)
既有藝術品和參考資料
無特定要求。
Cap'n Proto 具有支援的介面 沿用,包括多重繼承 (在混合樣式中)。