Scala 發佈版的二進制相容性

語言

當兩個版本的 Scala 二進制相容時,可以在一個 Scala 版本上編譯專案,並在執行時間連結到另一個 Scala 版本。安全的執行時間連結(僅限於此!)表示,當在混合場景中執行程式時,JVM 不會擲出 LinkageError(子類別),假設在編譯和執行於同一個 Scala 版本時不會產生任何錯誤。具體來說,這表示你可以對執行時間類別路徑中的外部依賴項使用與編譯時所使用的不同的 Scala 版本,只要它們是二進制相容的即可。換句話說,與在同一個 Scala 版本上編譯和執行所有內容相比,在不同的二進制相容版本上分開編譯不會造成問題。

我們使用 MiMa 自動檢查二進制相容性。我們努力維護標準函式庫的 行為(與連結相反)的類似不變性,但這並未經過機械檢查(Scala 不是證明助理,因此這超出了其類型系統的範圍)。

請注意,對於 Scala.js 和 Scala Native,二進制相容性問題會導致建置時間錯誤,而不是執行時間例外。它們會在各自的「連結」階段發生:Scala.js 的 {fast,full}LinkJS 和 Scala Native 的 nativeLink

向前和向後

我們區分向前和向後相容性(將這些視為版本序列的屬性,而不是個別版本的屬性)。維護向後相容性表示在較舊版本上編譯的程式碼將與使用較新版本編譯的程式碼連結。向前相容性允許你在新版本上編譯並在舊版本上執行。

因此,向後相容性排除移除(非私有)方法,因為舊版本可能會呼叫它們,而不知道它們將被移除,而向前相容性則禁止新增(非私有)方法,因為較新的程式可能會依賴它們,這將阻止它們在舊版本上執行(私有方法在此也獲得豁免,因為它們的定義和呼叫位置必須在同一個編譯單元中)。

保證和版本控制

對於 Scala 2,次要版本是版本中的第三個數字,例如 v2.13.10 中的 10。主要版本是第二個數字,在我們的範例中為 13。

Scala 2 保證在單一主要版本中,次要版本之間具有向後和向前相容性。

這些是嚴格的限制,但自 Scala 2.10.x 以來,它們對我們來說運作良好。它們並沒有阻止我們在次要版本中修復大量問題。到目前為止,該政策仍然適用於 Scala 2,儘管 存在移除向前相容性保證的提案

對於 Scala 3,次要版本是版本中的第二個數字,例如 v3.2.1 中的 2。第三個數字是修補程式版本。主要版本始終為 3。

Scala 3 保證在單一次要版本中,修補程式版本之間具有向後和向前相容性。特別是,這適用於整個 長期支援 (LTS) 系列(將從 Scala 3.3.x 開始)。

它還保證在整個 3.x 系列中,次要版本之間具有向後相容性,但不具有向前相容性。這表示使用任何 Scala 3.x 版本編譯的函式庫都可以在使用任何 Scala 3.y 版本編譯的專案中使用,其中 y >= x。

此外,Scala 3.x 提供相對於 Scala 2.13.y 的向後二進位相容性。使用 Scala 2.13.y 編譯的函式庫可以在使用 Scala 3.x 的專案中使用。此政策不適用於實驗性的 Scala 2 功能,特別包括巨集

一般來說,這些保證都不適用於實驗性功能和 API。

檢查

對於 Scala 函式庫工件(scala-libraryscala-reflectscala3-library),這些保證會使用 MiMa 機械檢查。

上述政策會延伸到由特定 Scala 編譯器版本編譯的函式庫。我們會盡一切努力來維護編譯器所產生工件的二進位相容性。然而,這無法機械檢查。因此,由於錯誤或無法預見的後果,使用不同編譯器版本重新編譯函式庫可能會影響其二進位 API。我們無法保證這永遠不會發生。

我們建議函式庫作者在發布之前使用 MiMa 自行驗證小版本的相容性。

TASTy 和 Pickle 相容性

二進位相容性是一個與目標平台(JVM、Scala.js 或 Scala Native)連結時間相關的概念。TASTy 和 Pickle 相容性類似,但適用於 Scala 編譯器的編譯時間。TASTy 適用於 Scala 3,Pickle 適用於 Scala 2。

如果函式庫是用較舊版本的編譯器編譯,我們會說該函式庫是向後 TASTy/Pickle 相容,如果它可以在使用較新編譯器版本編譯的應用程式中使用。同樣地,向前 TASTy/Pickle 相容性則相反。

與二進位相容性相同的政策適用於 TASTy/Pickle 相容性,儘管它們並未機械檢查。

函式庫作者可以使用 TASTy-MiMa 自動檢查其函式庫的 TASTy/Pickle 向後相容性。免責聲明:TASTy-MiMa 是個新專案。在這個階段,您可能會遇到錯誤。請將您發現的問題回報至其問題追蹤器。

具體來說

我們保證 "org.scala-lang" % "scala-library" % "2.N.x""org.scala-lang" % "scala-reflect" % "2.N.x" 產物的向前和向後相容性,但下列情況除外

  • scala.reflect.internalscala.reflect.io 套件,因為 scala-reflect 仍處於實驗階段,以及
  • scala.runtime 套件,其中包含在執行階段由產生程式碼所使用的類別。

我們強烈建議不要依賴 scala.concurrent.implscala.sys.process.*Implscala.reflect.runtime 的穩定性,儘管我們只會在這裡針對嚴重錯誤中斷相容性。

我們保證 "org.scala-lang" % "scala3-library_3" % "3.x.y" 產物的向後相容性。向前相容性僅在給定的 N 中保證 3.N.y

我們對模組(群組 ID org.scala-lang.modules 下的產物)強制執行向後(但非向前)二進位相容性。由於它們是選擇加入的,因此要求在類別路徑上擁有最新版本並非負擔。(在沒有向前相容性的情況下,產物的最新版本必須在執行階段類別路徑上,以避免連結錯誤。)

最後,從 Scala 2.11 到 Scala 2.13.0-M1,scala-library-all 會匯總構成 Scala 發行的所有模組。請注意,這表示它不提供向前二進位相容性,而核心 scala-library 人工製品則提供。我們認為 "scala-library-all" % "2.N.x" 所依賴的模組版本是官方 Scala 發行版的一部分,是標準版本。(發行版本身是由 scala-dist maven 人工製品定義的。)

此頁面的貢獻者