RFC-0024:強制來源相容性

RFC-0024:強制原始碼相容性
狀態已接受
區域
  • FIDL
說明

為 FIDL 語言繫結建立原始碼相容性標準,以及該標準的演進程序。

作者
提交日期 (年-月-日)2019-04-02
審查日期 (年-月-日)2019-04-11

摘要

為 FIDL 語言繫結建立原始碼相容性標準,以及該標準的演進程序。

提振精神

目前,針對語言繫結所產生的程式碼,幾乎沒有任何書面規則。這些類別應符合特定的 wire ABI,但除了這點之外,繫結作者可在 API 的塑造方式上有許多彈性。任何對 FIDL 定義所做的變更,都可能導致產生的繫結發生任意變更。

實際上,使用者會期待「常識」清單,列出應與來源相容的項目,例如定義新的頂層類型。不過,並沒有明確的規則指出這是事實。雖然這個案例似乎有點荒謬,但它說明瞭缺乏規格如何破壞使用者的期望。實際上發生過的實際例子包括在資料表中新增欄位、新增 xunion 變化版本,或是在結構體中新增預設欄位。使用者可以合理地預期這些變更不會造成來源中斷,但目前並沒有任何標準可明確指出這一點,而且所有這些變更都會導致目前一或多個語言繫結的來源層級中斷 (例如,由於 C++ 或 Go 中的定位初始化子,或 Rust 中的結構體模式)。

此外,許多 FIDL 語言繫結的擴充功能在過去曾因與來源相容性互動而遭拒。例如,將 copyclone 函式新增至不含句柄的類型。包含任意句柄的類型無法複製,因此在類型中新增句柄會導致該類型無法提供 clone 函式 (或無法提供有效的複製函式)。由於這項變更會影響來源相容性,因此已多次遭到拒絕,因為這項變更會在生成的 Rust 繫結中,根據沒有句柄的情況引入條件式 clone 函式。因此,Fuchsia 開發人員必須手動回卷自己的 clone 函式,並為透過這些手動回卷方法 clone 的 FIDL 產生類型新增包裝函式類型。本文件提出一致的標準,讓我們能夠評估這類功能,希望能為開發人員提供更符合人體工學、更友善的體驗,並免除繁瑣的程式碼。

設計

程序

這個 FTP 會建立初始的來源相容性限制組合。這份清單會在 Fuchsia 來源樹狀結構的文件中追蹤。您必須使用 FTP 程序新增其他來源相容性限制。為方便新增與新功能相關的來源相容性規則,我們將修訂 FTP 範本中的「向下相容性」部分,加入建議,以便引入新的來源相容性限制 (適用時)。

定義:來源相容性和轉換性

下列變更必須與原始碼相容 (即不會破壞原始碼) 或可轉換

原始碼相容性變更不得導致產生 FIDL 繫結公開 API 的任何有效 (編譯) 用途的原始碼中斷。針對限制哪些功能屬於「公開 API」,以及哪些功能不屬於「公開 API」的定義和可行性,我們有合理的論點;因此,為了符合本文的目的,我們將「公開 API」定義為任何使用產生的繫結,但不需使用非凡的語言技巧 (例如反射) 或開發人員明確意圖違反隱私權 (例如呼叫 __private_dont_use_me_function_2())。所有其他公開的 API (例如位置初始化、模式比對等) 都必須受到限制,以免使用者程式遭到 FIDL 程式庫的來源相容性變更破壞。

可轉換的變更是指「可以」編寫程式碼的變更,這些程式碼會在變更前後進行編譯。每個可轉換的來源相容性規則都必須明確指定 API 在轉換期間的「用途」。

初始來源相容性限制

以下列出必須與來源相容的變更:

  • 新增頂層項目 (通訊協定、類型或常數)。
    • 動機:使用者希望能夠宣告新的通訊協定、類型和常數,而不會影響現有 FIDL 程式庫的使用者。
    • 例外狀況:使用「*」或從命名空間全面匯入的情況,可能會因為不同程式庫中同名項目之間的歧義而發生錯誤。
  • 在非嚴格資料表中新增欄位。
    • 動機:資料表的設計可輕鬆擴充,且應支援額外欄位,而不會造成損壞。如要選擇採用破損,可以使用 strict 修飾符。
  • 在非嚴格可延伸的聯結中新增變化版本。
    • 動機:可擴充的聯集可輕鬆擴充,且應支援其他變化版本,而不會造成損壞。如要選擇啟用破損,可以使用 strict 修飾符。
  • 將成員新增至非嚴格枚舉
    • 動機:非嚴格枚舉會隱含選擇擴充性,且應可在不破壞來源的情況下擴充。
  • 將成員新增至非嚴格「位元」
    • 動機:非嚴格位元會隱含選擇擴充性,且應可在不破壞來源的情況下擴充
  • [Layout = "Simple"] 新增至現有通訊協定
    • 動機:[Layout = "Simple"] 的存在目的,是為了在簡單的 C 繫結中啟用使用。符合規範的現有通訊協定不應需要破壞來源變更,才能指定可在簡易 C 繫結中使用。
  • [MaxHandles] 新增至現有類型
    • 動機:[MaxHandles] 的用途是提供類型的額外資訊,以便更彈性地使用。不應要求進行重大來源變更,才能指定類型已包含固定的句柄數量上限,並假設該類型會繼續包含最多該數量的句柄。

以下列出必須進行轉換的變更:

  • [Transitional] 新增至方法
    • 用途:在將 [Transitional] 屬性新增至該方法前後,必須能夠實作通訊協定,並提供使用相同來源的方法實作。
    • 動機:只要所有現有實作項目都能逐步調整,就必須能夠逐步新增或移除通訊協定的方法。
  • 新增 [Transitional] 方法
    • 用途:在新增 [Transitional] 方法之前和之後,都必須能夠使用相同的來源實作通訊協定 (不過,API 在轉換期間不必允許實作該方法)。
    • 動機:只要所有現有實作項目都能逐步調整,就必須能夠逐步新增或移除通訊協定的方法。
  • 移除 [Transitional] 方法
    • 用途:在移除 [Transitional] 方法前後,必須能夠使用相同的來源實作通訊協定 (不過 API 在轉換期間不必允許實作該方法)。
    • 動機:只要所有現有的實作項目都能逐步調整,就必須能夠逐步新增或移除通訊協定的方法。
  • 移除非嚴格表格的欄位
    • 用途:在移除資料表欄位前後,必須能夠使用相同的來源建立資料表並存取其欄位 (除了要移除的欄位)。
    • 動機:資料表的設計可輕鬆進行演進,且應支援移除作業,而不會造成損壞。如要選擇採用破損,您可以在資料表上使用 strict 修飾符。
  • 移除非嚴格可延伸聯集的變化版本
    • 用途:在移除 xunion 變數之前和之後,必須能夠使用相同的來源建立 xunion 並存取其變數 (除了要移除的變數)。
    • 動機:xunion 的設計可輕鬆進行演進,且應支援移除而不會中斷。如要選擇採用破損,您可以在資料表上使用 strict 修飾符。
  • 將類型標示為 strict
    • 用途:在新增 strict 之前和之後,必須能夠使用相同來源存取資料表或「位元」的所有欄位,以及枚舉或 xunion 的所有變化版本。
    • 動機:strict 應在類型穩定後加入類型宣告,以便提供更完善的推理和開發人員工具。不過,這項要求僅適用於可轉換的變更,而非不中斷的變更,因為可擴充類型可能會允許存取未知的欄位或變化版本。這些功能對 strict 類型來說並不合理,因為系統會拒絕未知的欄位或變化版本。
  • [Transitional] 新增至枚舉或位元、資料表欄位或可擴充聯集的變數。
    • 用途:在 [Transitional] 推出前後,您必須能夠存取所有非轉換成員/位元/欄位/變體,並使用相同來源建構不含 [Transitional] 值的列舉/位元/資料表/可擴充聯集。
    • 動機:必須能夠逐步移除成員、欄位或變數。
  • 新增枚舉或位元的新成員、表格的欄位,或標示為 [Transitional] 的可擴充聯集的變化版本。
    • 用途:在引入新 [Transitional] 欄位之前和之後,必須能夠存取所有非轉換成員/位元/欄位/變體,並使用相同來源建構不含 [Transitional] 值的 enum/位元/表格/可擴充聯集。
    • 動機:必須能夠逐步新增成員、欄位或變化版本。
  • 移除 enum 或位元、資料表欄位,或標示為 [Transitional]. 的可擴充聯集變化版本的成員
    • 用途:您必須能夠在移除 [Transitional] 欄位前後,使用相同來源存取所有非過渡成員/位元/欄位/變體,並建構不含 [Transitional] 值的列舉/位元/表格/可擴充聯合的值。
    • 動機:必須能夠逐步移除成員、欄位或變數。

以下是這份清單中未列出的潛在限制,以及未列入的原因:

  • 新增或移除結構體中的欄位 (預設或非預設)
    • 這是會破壞 ABI 的變更,因此需要其他重大努力,才能確保相容的轉換。如要讓這項變更不會造成中斷,就必須移除任何「針對所有欄位」類型的型別推理,包括自動方法衍生 (例如「此型別是否包含任何浮點值」)、位置初始化器,以及完整欄位比對和建構。
  • 在嚴格表格和 xunion 中新增或移除欄位/變化版本 (預設或非預設)
    • strict 旨在啟用其他開發人員工具,這些工具會依據「for all fields」類型的推理方式來判斷型別,包括自動方法衍生 (例如「此型別是否包含任何浮點值」)、位置初始化器,以及完整的欄位比對和建構。強制這項變更為非破壞性變更,將會阻礙這項目的。
  • 將含有句柄的欄位或子類加入未標示為 [MaxHandles] 的類型
    • 將欄位新增至嚴格類型或結構體,已是其他原因造成的來源變更,因此新增具備句柄的欄位也是類似的變更,可能會影響隨後產生的 API。

導入策略

這項 FTP 會建立初步的語言相容性標準。錯誤會提交並指派給每個語言繫結的作者,以確保其語言繫結符合規定。

人體工學

這項異動可為原始碼相容性設定明確的標準,讓您更輕鬆地使用 FIDL,並允許自動檢查,以及更輕鬆地手動檢查 FIDL 變更的原始碼相容性,同時為繫結作者提供更明確的原始碼相容性指引,讓他們能夠自由地建立符合語言慣例的繫結,同時遵守專案的標準規定。

說明文件和範例

在這個 FTP 獲得核准後,我們會將 FTP 建立的程序,以及來源相容性規則本身,連同其他 FIDL 參考文件一併發布。

回溯相容性

套用建議的指引可能需要變更繫結和使用這些繫結的方式,這取決於各繫結作者如何處理這些變更。

這個部分 (「向下相容性」部分) 將修訂為納入以下文字:

「如果您要推出新的資料類型或語言功能,請考量使用者會對 FIDL 定義做出哪些變更,且不會影響產生程式碼的使用者。如果您的功能對產生的語言繫結設有任何新的來源相容性限制,請在此列出這些限制。」

請注意,您應將「來源相容性」文字納入此 FTP 的實際連結,也就是:

[source compatibility](/docs/contribute/governance/rfcs/0024_mandatory_source_compatibility.md)

成效

這項 FTP 不會限制執行階段行為,但對來源 API 的限制可能會導致語言繫結作者設計效能較高或較低的 API。在引入新的來源相容性限制時,請考慮在支援的語言中建立高效繫結的可行性。

這項功能可能會影響編譯時間效能,因為它會推向需要大量內嵌和編譯器最佳化模式的模式,以便提升效能 (例如將複雜的建構工具 API 最佳化為簡單的結構體初始化)。繫結作者應盡力做出設計選擇,以免大幅影響編譯時間,但特定語言 API 的編譯時間後果不一定會導致引入新的來源相容性限制。

安全性

這項功能不會影響安全性。

測試

許多來源相容性規則的格式為「在變更前編譯的任何使用者程式碼,在變更後都不能存在。」很遺憾,這些限制很難或無法測試,因為必須在變更前列舉 API 的所有可能用途。

不過,我們可以 (也應該) 在 FIDL 變更測試套件中新增項目,以便顯示在變更前後,API 確實存在某些用途。這是符合來源相容性規定的必要條件,但並非充分條件。

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

  • 請勿引入這類規格。允許繫結作者選擇他們希望變更內容是否會造成中斷。這與目前的實際狀態大致相同,但會讓繫結作者享有比目前系統實際授予的更大彈性,因為在目前的系統中,某些來源相容性不友善的變更已遭到反對。
  • 請建立規格,說明哪些變更「可」造成來源中斷,而非哪些變更「不」可造成來源中斷。這項做法較難強制執行,且需要繫結作者預測變更,以便在變更發生時,確保繫結仍與來源相容。
  • 稍微修改一下,即可指定「是」和「否」的變更,未指定的變更則會預設為某種方式。這基本上與此 FTP 或上述替代方案相同,但會設定更正式的預期,說明記錄不同 FIDL 變更的效果。

既有技術與參考資料

我們先前曾嘗試透過 [MaxHandles] 屬性引入可進化限制。本提案的前半段已討論過這項設計和預期的修改方式。