Scala 3 Migration Guide

Interoperability

Language

To use a module or library, the compiler reads the signatures of its definitions from the class files. Scala 2.13 stores the signatures in the Pickle format, Scala 3 in the TASTy format.

Scala 3 Can Use Scala 2.13 Binaries

The Scala 3 compiler reads the Scala 2.13 Pickle format, so a Scala 3 module can depend on modules and libraries compiled with Scala 2.13. This works with every Scala 3 version.

Scala 3 module depending on a Scala 2.13 artifact

In sbt:

// build.sbt
lazy val foo = project.in(file("foo"))
  .settings(scalaVersion := "3.9.0")
  .dependsOn(bar)

lazy val bar = project.in(file("bar"))
  .settings(scalaVersion := "2.13.18")

For a published Scala 2.13 library, CrossVersion.for3Use2_13 makes sbt resolve bar_2.13 instead of bar_3:

lazy val foo = project.in(file("foo"))
  .settings(
    scalaVersion := "3.9.0",
    libraryDependencies += ("org.bar" %% "bar" % "1.0.0").cross(CrossVersion.for3Use2_13)
  )

The Scala 3 compiler cannot expand Scala 2 macros, see Macro Libraries.

The Standard Library

Up to 3.7, Scala 3 uses the Scala 2.13 standard library. Since 3.8, the standard library is compiled with Scala 3. It is binary compatible with the 2.13 standard library, so code compiled with an earlier Scala 3 version or Scala 2.13 continues to work.

Scala 2.13 Can Use Scala 3 Binaries

With the -Ytasty-reader option, Scala 2.13 can read the TASTy format of Scala 3 up to version 3.7. It cannot read code compiled with Scala 3.8 or later.

Scala 2 module depending on a Scala 3 artifact

In sbt:

// build.sbt
lazy val foo = project.in(file("foo"))
  .settings(
    scalaVersion := "2.13.18",
    scalacOptions += "-Ytasty-reader"
  )
  .dependsOn(bar)

lazy val bar = project.in(file("bar"))
  .settings(scalaVersion := "3.3.8")

Supported Features

The TASTy reader supports all the traditional language features as well as the following Scala 3 features:

It partially supports:

It does not support the more advanced features:

Using an unsupported definition is an error at the use site; other definitions of the same module can still be used.

Mixing Scala 2.13 and Scala 3 Modules

During a migration, a build can contain both Scala 2.13 and Scala 3 modules that depend on each other in both directions.

Sandwich pattern

A library can only be on the classpath once: either as foo_2.13 or as foo_3, not both. sbt reports an error when a build resolves both. While the build is mixed, the project will use the _2.13 artifacts of all Scala libraries, using CrossVersion.for3Use2_13 in the Scala 3 modules.

For example, if the project uses cats_2.13 in some 2.13 module, downstream dependencies such as http4s need to stay on _2.13 too, even if they are only used in Scala 3 modules.

Disclaimer for library maintainers

Unless you know exactly what you are doing, it is discouraged to publish a Scala 3 library that depends on a Scala 2.13 library (the scala-library being excluded) or vice versa. The reason is to prevent library users from ending up with two conflicting versions foo_2.13 and foo_3 of the same foo library in their classpath, this problem being unsolvable in some cases.

Contributors to this page: