Scala 3.1.2 released!

Tuesday 12 April 2022

Paweł Marks, VirtusLab

We are happy to announce the release of Scala 3.1.2. This new release brings a few significant improvements awaited by the community.

Configurable Scala output version

First and foremost, after months of brainstorming and testing, we are bringing an experimental possibility to configure the Scala output version. This means that the compiler can now generate TASTy files and classfiles in a format used by an older minor version of Scala (which can currently be only 3.0.x) effectively specifying the minimum version of the compiler that is able to read your compiled code.

If you are a library maintainer, you may have faced a dilemma, should you update the Scala version to 3.1 or stay on 3.0. On the one hand, updating would bring you all bug fixes and enhancements from the newest version of the compiler. On the other, all new releases of your library would be unusable for all the users that are, for some reason, stuck on Scala 3.0.

Now, this tradeoff is no more. When compiling your library with Scala 3.1.2, you can set your output version to Scala 3.0. Then your library can be used by code compiled with Scala 3.0, 3.1, or any future version. All produced TASTy files will be compatible with Scala 3.0 and newer.

While the compiler setting itself is not explicitly marked as experimental (its corresponding flag doesn’t have a -X or -Y prefix in its name), its role in the broader ecosystem of Scala libraries is yet to be determined. We are eagerly awaiting feedback from the maintainers of libraries. Hearing your opinions will allow us to choose the right strategy for supporting code compiled for previous Scala versions so that we can find a balance between compatibility and a possibility for the language to evolve.

Current support

You can set the Scala output version by using a new compiler flag named -scala-output-version with a minor release version as an argument. You may remember this flag as -scala-target or -Xscala-release in design discussions and unstable builds. Those names are not supported in the stable release.

Sbt, starting from version 1.7.0-M1, has a setting scalaOutputVersion that not only sets the compiler flag mentioned above but also determines which version of the standard library will be specified as a dependency of your project. For example, adding

ThisBuild / scalaVersion       := "3.1.2"
ThisBuild / scalaOutputVersion := "3.0.2"

to your build definition will make your project be compiled using the latest currently available version of the compiler but it will be available as a dependency for other projects compiled with both 3.1.x and 3.0.x. Also the standard library from Scala 3.0.2 will be used at runtime when you use sbt run or sbt test. This should help you find possible runtime issues earlier when you intend your library to be compatible with earlier compilers.

scalaOutputVersion was designed to work smoothly also in cases when you’re still forced to cross-compile anyway (e.g. if your project contains macros but you want to support both Scala 2 and 3). In such situation you should only make sure that scalaOutputVersion is set to the same value as scalaVersion (which is equivalent to leaving scalaOutputVersion undefined) if the compiler in scalaVersion doesn’t yet support the -scala-output-version flag. E.g.

ThisBuild / scalaVersion := "3.1.2"
ThisBuild / crossScalaVersions := List("2.13.8", "3.1.2")
ThisBuild / scalaOutputVersion := {
  CrossVersion.partialVersion(scalaVersion.value) match {
    case Some((3, _)) => "3.0.2"
    case _ => scalaVersion.value
  }
}

Changes to other compatibility flags

We realized that there is some confusion about current output compatibility flags, and adding a new one would only make it worse. So, we have decided to rename existing flags. -release is now -java-output-version, and -Xtarget is -Xunchecked-java-output-version. The old names are left as aliases for the sake of compatibility.

Other improvements

  • You can now pass -Xmacro-settings flag during the compilation to customize the behavior of macros in your code. This feature is still experimental. For example, you can compile following code with -Xmacro-settings:present,key=value:

    //> using options "-Xmacro-settings:present,key=value"
    
    import scala.quoted.*
    
    inline def customizable = ${ customizableImpl }
    
    def customizableImpl(using Quotes) =
      import quotes.reflect.*
      val settings = CompilationInfo.XmacroSettings
    
      val present    = settings.contains("present")       // true
      val notPresent = settings.contains("not-present")   // false
      val withValue  = settings.collectFirst {            // Some("value")
        case s"key=$value" => value
      }
    
      ??? // Do something fancy with your settings
    
  • You can run scala command with -e flag to quickly execute a Scala statement from the command line.

      scala -e "println(22*38)"
    

    will print 836 on standard output and exit the Scala process.

  • There are new optimizations in the typer that may results in significant speedups in some cases. You can find more information and benchmark results in the related pull request.

Contributors

Thank you to all the contributors who made this release possible.

According to git shortlog -sn --no-merges 3.1.1..3.1.2 these are:

  57  Martin Odersky
  44  Nicolas Stucki
  28  Dale Wijnand
  20  Paweł Marks
  18  Jamie Thompson
  16  Andrzej Ratajczak
  16  Filip Zybała
  16  Guillaume Martres
  15  Michał Pałka
  10  Olivier Blanvillain
   9  Som Snytt
   8  Matt Bovel
   7  Fengyun Liu
   7  Tomasz Godzik
   6  danicheg
   6  Sébastien Doeraene
   6  Gagandeep Kalra
   6  oronpo
   5  Seth Tisue
   5  Arman Bilge
   4  Stephane MICHELOUD
   4  noti0na1
   3  Phil
   3  adampauls
   3  ghostbuster91
   3  Eric Torreborre
   2  Matthieu Bovel
   2  philwalk
   2  Kacper Korban
   2  Ruslan Shevchenko
   2  Oron Port
   2  Chris Kipp
   1  Andrzej Ressel
   1  Anatolii Kmetiuk
   1  Arthur Sengileyev
   1  Cédric Chantepie
   1  Denis Zolkin
   1  Georgi Krastev
   1  Hugo van Rijswijk
   1  Jakob Odersky
   1  Julien Richard-Foy
   1  Kien Dang
   1  Natsu Kagami
   1  Ondrej Lhotak
   1  Ondřej Lhoták
   1  Rikito Taniguchi
   1  SDSR
   1  Tom Grigg
   1  Yang, Bo
   1  comcx
   1  kenji yoshida
   1  mzcu
   1  soronpo
   1  Łukasz Wroński
   1  Adrien Piquerez