RFC-0024:強制來源相容性

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

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

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

摘要

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

提振精神

目前,語言繫結產生的程式碼很少有書面規則。預期這些函式會符合特定線路 ABI,但除此之外,繫結作者在塑造 API 方面有很大的自由度。FIDL 定義的任何變更,都可能導致產生的繫結發生任意變更。

實際上,使用者會期望看到「常識」清單,列出應與來源相容的項目,例如定義新的頂層型別。不過,沒有明確的規則說明這類情況。 雖然這個案例有點荒謬,但說明瞭缺乏規格會如何破壞使用者的期望。實際發生的例子包括在表格中新增欄位、新增 xunion 變體,或在結構體中新增預設欄位。使用者有理由認為這些變更不會導致來源中斷,但目前沒有相關標準,而且所有這些變更都會導致一或多個語言繫結的來源層級中斷 (例如,由於 C++ 或 Go 中的位置初始值,或是 Rust 中的結構體模式)。

此外,過去有許多極為實用的 FIDL 語言繫結擴充功能,因與來源相容性互動而遭到拒絕。例如,將 copyclone 函式新增至不含控制代碼的型別。含有任意控制代碼的型別無法複製,因此將控制代碼新增至型別會導致該型別無法提供 clone 函式 (或至少會導致該型別無法提供正常運作的複製函式)。由於會影響來源相容性,因此我們多次拒絕這項變更,也就是根據控點是否不存在,在產生的 Rust 繫結中導入 clone 函式的條件式納入。因此,Fuchsia 開發人員必須手動推出自己的 clone 函式,並為透過這些手動推出方法傳遞的 FIDL 產生型別新增包裝函式型別。clone本文建議採用一致的標準來評估這類功能,希望為開發人員提供更符合人體工學、更友善且免除樣板的體驗。

設計

流程

這份 FTP 會建立一組初始的來源相容性限制。這份清單會記錄在 Fuchsia 來源樹狀結構的文件中。必須使用 FTP 程序新增其他來源相容性限制。為方便新增與新功能相關的來源相容性規則,FTP 範本的「向後相容性」部分將會修訂,納入導入新來源相容性限制的建議 (如適用)。

定義:原始碼相容性和轉換性

下列變更必須與來源相容 (即不會破壞來源),或可轉換

原始碼相容變更不得導致任何有效 (編譯) 使用所產生 FIDL 繫結的公開 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] 欄位前後使用相同來源。
    • 動機:必須能夠逐步新增成員、欄位或變體。
  • 移除列舉或位元成員、資料表欄位,或是標示為 [Transitional]. 的可擴充聯集變體
    • 用途:必須能夠存取所有非過渡成員/位元/欄位/變體,並建構不含 [Transitional] 值的列舉/位元/表格/可擴充聯集值,且在移除 [Transitional] 欄位前後使用相同來源。
    • 動機:必須能夠逐步移除成員、欄位或變體。

以下是可能遭排除的限制,以及排除原因:

  • 從結構體新增或移除欄位 (預設或非預設)
    • 這是 ABI 破壞性變更,需要其他重大工作,才能確保相容的轉移作業。如要避免這項重大變更,必須排除所有「適用於所有欄位」的型別推理,包括自動方法衍生 (例如「這個型別是否包含任何浮點數」)、位置初始化程式,以及詳盡的欄位比對和建構。
  • 從嚴格資料表和 xunion 新增或移除欄位/變體 (預設或非預設)
    • strict 的用途是啟用額外的開發人員工具,這些工具依賴「適用於所有欄位」的型別推理,包括自動方法衍生 (例如「這個型別是否包含任何浮點數」)、位置初始化程式,以及詳盡的欄位比對和建構。如果強制將這項變更設為非破壞性,就會阻礙這個目的。
  • 將含有控制代碼的欄位或變體新增至未標示 [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] 屬性導入可演化性限制。這項設計和預期修改內容已在本提案的先前部分討論過。