In your code you can use public types and terms, and call public methods that are defined in a different module or library. It works well as long as the type checker, which is the compiler phase that validates the semantic consistency of the code, is able to read the signatures of those types, terms and methods, from the class files containing them.
In Scala 2 the signatures are stored in a dedicated format called the Pickle format. In Scala 3 the story is a bit different because it relies on the TASTy format which is a lot more than a signature layout. But, for the purpose of moving from Scala 2.13 to Scala 3, only the signatures are useful.
The Scala 3 Unpickler
The first piece of good news is that the Scala 3 compiler is able to read the Scala 2.13 Pickle format and thus it can type check code that depends on modules or libraries compiled with Scala 2.13.
The Scala 3 unpickler has been extensively tested in the community build for many years now. It is safe to use.
A Scala 3 module can depend on a Scala 2.13 artifact
As an sbt build it can be illustrated by (sbt 1.5.0 or higher is required):
lazy val foo = project.in(file("foo")) .settings(scalaVersion := "3.0.0") .dependsOn(bar) lazy val bar = project.in(file("bar")) .settings(scalaVersion := "2.13.6")
Or, in case bar is a published Scala 2.13 library, we can have:
lazy val foo = project.in(file("foo")) .settings( scalaVersion := "3.0.0", libraryDependencies += ("org.bar" %% "bar" % "1.0.0").cross(CrossVersion.for3Use2_13) )
CrossVersion.for3Use2_13 in sbt to resolve
bar_2.13 instead of
The Standard Library
One notable example is the Scala 2.13 library. We have indeed decided that the Scala 2.13 library is the official standard library for Scala 3.
Let’s note that the standard library is automatically provided by the build tool, you should not need to configure it manually.
The Scala 2.13 TASTy Reader
The second piece of good news is that the Scala 2.13 TASTy reader, which enables consuming Scala 3 libraries has been shipped since Scala 2.13.4.
The TASTy reader is very new. That’s why it is only available under the
The TASTy reader supports all the traditional language features as well as the following brand-new features:
- Intersection Types
- Opaque Type Aliases
- Type Lambdas
- Contextual Abstractions (new syntax)
- Open Classes (and inheritance of super traits)
- Export Clauses
We have limited support on:
More exotic features are not supported:
- Context Functions
- Polymorphic Function Types
- Trait Parameters
- Functions and Tuples larger than 22 parameters
- Match Types
- Union Types
- Multiversal Equality (unless explicit)
- Inline (including Scala 3 macros)
- Kind Polymorphism (the
A Scala 2.13 module can depend on a Scala 3 artifact
By enabling the TASTy reader with
-Ytasty-reader, a Scala 2.13 module can depend on a Scala 3 artifact.
As an sbt build it can be illustrated by:
lazy val foo = project.in.file("foo") .settings( scalaVersion := "2.13.6", scalacOptions += "-Ytasty-reader" ) .dependsOn(bar) lazy val bar = project.in(file("bar")) .settings(scalaVersion := "3.0.0")
Or, in case
bar is a published Scala 3 library:
lazy val foo = project.in.file("foo") .settings( scalaVersion := "2.13.6", scalacOptions += "-Ytasty-reader", libraryDependencies += ("org.bar" %% "bar" % "1.0.0").cross(CrossVersion.for2_13Use3) )
CrossVersion.for2_13Use3, we use
CrossVersion.for3Use2_13 in sbt to resolve
bar_3 instead of
In short, we have backward and forward compatibility and so migration can happen gradually.
You can port a big Scala application one module at a time, even if its library dependencies have not yet been ported (excepting the macro libraries).
During the transition period, you can have a Scala 3 module layered in between two 2.13 modules.
This is permitted as long as all libraries are resolved to a single binary version: you can have
lib-bar_2.13 in the same classpath, but you cannot have
The inverted pattern, with a 2.13 module in the middle, is also possible.
Disclaimer for library maintainers
Using the interoperability between Scala 2.13 and Scala 3 in a published library is generally not safe for your end-users.
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_3of the same foo library in their classpath, this problem being unsolvable in some cases.