Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add reference docs for forward compatibility feature #2301

Merged
merged 1 commit into from
Jan 31, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
33 changes: 4 additions & 29 deletions _scala3-reference/language-versions.md
Original file line number Diff line number Diff line change
@@ -1,36 +1,11 @@
---
title: Language Versions
type: chapter
description: This page lists the different flavours of language supported by the Scala 3 compiler.
num: 100
previous-page: overview
previous-page: /scala3/reference/syntax
next-page: /scala3/reference/language-versions/source-compatibility
---

The default Scala language version currently supported by the Dotty compiler is `3.0`. There are also other language versions that can be specified instead:
This chapter explains how different versions of the language interact with each other regarding their inputs and outputs.

- `3.0-migration`: Same as `3.0` but with a Scala 2 compatibility mode that helps moving Scala 2.13 sources over to Scala 3. In particular, it

- flags some Scala 2 constructs that are disallowed in Scala 3 as migration warnings instead of hard errors,
- changes some rules to be more lenient and backwards compatible with Scala 2.13
- gives some additional warnings where the semantics has changed between Scala 2.13 and 3.0
- in conjunction with `-rewrite`, offer code rewrites from Scala 2.13 to 3.0.

- `future`: A preview of changes introduced in the next versions after 3.0. In the doc pages here we refer to the language version with these changes as `3.1`, but it might be that some of these changes will be rolled out in later `3.x` versions.

Some Scala-2 specific idioms will be dropped in this version. The feature set supported by this version will be refined over time as we approach its release.

- `future-migration`: Same as `future` but with additional helpers to migrate from `3.0`. Similarly to the helpers available under `3.0-migration`, these include migration warnings and optional rewrites.

There are two ways to specify a language version.

- With a `-source` command line setting, e.g. `-source 3.0-migration`.
- With a `scala.language` import at the top of a source file, e.g:

```scala
package p
import scala.language.`future-migration`

class C { ... }
```

Language imports supersede command-line settings in the source files where they are specified. Only one language import specifying a source version is allowed in a source file, and it must come before any definitions in that file.
Additional information on interoperability and migration between Scala 2 and 3 can be found [here]({% link _overviews/scala3-migration/compatibility-intro.md %}).
38 changes: 38 additions & 0 deletions _scala3-reference/language-versions/binary-compatibility.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
---
title: Binary Compatibility
type: section
num: 102
previous-page: /scala3/reference/language-versions/source-compatibility
---

In Scala 2, different minor versions of the compiler were free to change the way how they encoded different language features in JVM bytecode. So each bump of the compiler's minor version resulted in breaking the binary compatibility, and if a project had any Scala dependencies they all needed to be (cross-)compiled to the same minor Scala version that was used in that project itself. On the contrary, Scala 3 has a stable encoding into JVM bytecode.

In addition to classfiles, the compilation process in Scala 3 also produces files with `.tasty` extension. [TASTy]({% link scala3/guides/tasty-overview.md %}) files represent fully elaborated Scala programs in the sense that they contain all the information that has been inferred by the compiler during the compilation (like contextual parameters and type parameters). Some of this information is lost during the generation of bytecode so Scala 3 compilers read TASTy files during compilation in addition to classfiles to know the exact types of values, methods, etc. in already compiled classes (although compilation from TASTy files only is also possible). TASTy files are also typically distributed together with classfiles in published artifacts.

TASTy format is extensible but it preserves backward compatibility and the evolution happens between minor releases of the language. This means a Scala compiler in version `3.x1.y1` is able to read TASTy files produced by another compiler in version `3.x2.y2` if `x1 >= x2` (assuming two stable versions of the compiler are considered - `SNAPSHOT` or `NIGHTLY` compiler versions can read TASTy in an older stable format but their TASTY versions are not compatible between each other even if the compilers have the same minor version; also compilers in stable versions cannot read TASTy generated by an unstable version).

TASTy version number has the format of `<major_version>.<minor_version>-<experimental_version>` and the numbering changes in parallel to language releases in such a way that a bump in language minor version corresponds to a bump in TASTy minor version (e.g. for Scala `3.0.0` the TASTy version is `28.0-0`). Experimental version set to 0 signifies a stable version while others are considered unstable/experimental. TASTy version is not strictly bound to the data format itself - any changes to the API of the standard library also require a change in TASTy minor version.

Being able to bump the compiler version in a project without having to wait for all of its dependencies to do the same is already a big leap forward when compared to Scala 2. However, we might still try to do better, especially from the perspective of authors of libraries.
If you maintain a library and you would like it to be usable as a dependency for all Scala 3 projects, you would have to always emit TASTy in a version that would be readble by everyone, which would normally mean getting stuck at 3.0.x forever.

To solve this problem a new experimental compiler flag `-Yscala-release <release-version>` (available since 3.1.2-RC1) has been added. Setting this flag makes the compiler produce TASTy files that should be possible to use by all Scala 3 compilers in version `<release-version>` or newer (this flag was inspired by how `-release` works for specifying the target version of JDK). More specifically this enforces emitting TASTy files in an older format ensuring that:
* the code contains no references to parts of the standard library which were added to the API after `<release-version>` and would crash at runtime when a program is executed with the older version of the standard library on the classpath
* no dependency found on the classpath during compilation (except for the standard library itself) contains TASTy files produced by a compiler newer than `<release-version>` (otherwise they could potentially leak such disallowed references to the standard library).

If any of the checks above is not fulfilled or for any other reason older TASTy cannot be emitted (e.g. the code uses some new language features which cannot be expressed the the older format) the entire compilation fails (with errors reported for each of such issues).

As this feature is experimental it does not have any special support in build tools yet (at least not in sbt 1.6.1 or lower).
julienrf marked this conversation as resolved.
Show resolved Hide resolved
E.g. when a project gets compiled with Scala compiler `3.x1.y1` and `-Yscala-release 3.x2` option and then published using sbt
then the standard library in version `3.x1.y1` gets added to the project's dependencies instead of `3.x2.y2`.
When the dependencies are added to the classpath during compilation with Scala `3.x2.y2` the compiler will crash while trying to read TASTy files in the newer format.
A currently known workaround is to modify the build definition of the dependent project by explicitly overriding the version of Scala standard library in dependencies, e.g.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a known workaround that could be applied on the library itself, instead of the modules that depend on the library? Maybe a way to override the package task in sbt to override the version of the dependency to scala3-library? Maybe @eed3si9n knows a trick?


```scala
dependencyOverrides ++= Seq(
scalaOrganization.value %% "scala3-library" % scalaVersion.value,
scalaOrganization.value %% "scala3-library_sjs1" % scalaVersion.value // for Scala.js projects
Comment on lines +33 to +34
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would this work?

Suggested change
scalaOrganization.value %% "scala3-library" % scalaVersion.value,
scalaOrganization.value %% "scala3-library_sjs1" % scalaVersion.value // for Scala.js projects
scalaOrganization.value %% "scala3-library" % scalaVersion.value,
scalaOrganization.value %%% "scala3-library" % scalaVersion.value // for Scala.js projects

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried this but for some reason this didn't seem to work

)
```

The behaviour of `-Yscala-release` flag might still change in the future, especially it's not guaranteed that every new version of the compiler would be able to generate TASTy in all older formats going back to the one produced by `3.0.x` compiler.
38 changes: 38 additions & 0 deletions _scala3-reference/language-versions/source-compatibility.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
---
title: Source Compatibility
type: section
num: 101
previous-page: /scala3/reference/language-versions
next-page: /scala3/reference/language-versions/binary-compatibility
---

Scala 3 does NOT guarantee source compatibility between different minor language versions (e.g. some syntax valid in 3.x might get deprecated and then phased out in 3.y for y > x). There are also some syntax structures that were valid in Scala 2 but are not anymore in Scala 3. However the compiler provides a possibility to specify the desired version of syntax used in a particular file or globally for a run of the compiler to make migration between versions easier.

The default Scala language syntax version currently supported by the Dotty compiler is [`3.0`](https://scala-lang.org/api/3.x/scala/runtime/stdLibPatches/language$$3/0$.html). There are also other language versions that can be specified instead:

- [`3.0-migration`](https://scala-lang.org/api/3.x/scala/runtime/stdLibPatches/language$$3/0-migration$.html): Same as `3.0` but with a Scala 2 compatibility mode that helps moving Scala 2.13 sources over to Scala 3. In particular, it

- flags some Scala 2 constructs that are disallowed in Scala 3 as migration warnings instead of hard errors,
- changes some rules to be more lenient and backwards compatible with Scala 2.13
- gives some additional warnings where the semantics has changed between Scala 2.13 and 3.0
- in conjunction with `-rewrite`, offer code rewrites from Scala 2.13 to 3.0.

- [`future`](https://scala-lang.org/api/3.x/scala/runtime/stdLibPatches/language$$future$.html): A preview of changes introduced in the next versions after 3.0. In the doc pages here we refer to the language version with these changes as `3.1`, but it might be that some of these changes will be rolled out in later `3.x` versions.

Some Scala 2 specific idioms will be dropped in this version. The feature set supported by this version will be refined over time as we approach its release.

- [`future-migration`](https://scala-lang.org/api/3.x/scala/runtime/stdLibPatches/language$$future-migration$.html): Same as `future` but with additional helpers to migrate from `3.0`. Similarly to the helpers available under `3.0-migration`, these include migration warnings and optional rewrites.

There are two ways to specify a language version :

- with a `-source` command line setting, e.g. `-source 3.0-migration`.
- with a `scala.language` import at the top of a source file, e.g:

```scala
package p
import scala.language.`future-migration`

class C { ... }
```

Language imports supersede command-line settings in the source files where they are specified. Only one language import specifying a source version is allowed in a source file, and it must come before any definitions in that file.