Scala 3.8.0 release thread

Scala 3.8.0-RC1 is now available for public tests!

Highlights of the release

  • Require JDK 17+ #24146
  • Scala Standard Library is now compiled and published using Scala 3
  • Add explicit null checks to Scala 3 Standard Library #23566
  • Add capture-checking to Scala 3 Standard Library #23688
  • Add capture-checking to Scala 2 collections #23769
  • Extract REPL to be its own artifact #24243
  • SIP-57: Make runtimeChecked a standard feature #23262
  • SIP-62: Make better-fors a stable feature #23630
  • Preview SIP-71: Make into preview feature #24090
  • Experimental SIP-67: Strict equality pattern matching #23803
  • Experimental SIP-70: Allow multiple spreads in function arguments #23855
  • Experimental SIP-75: Allow single-line lambdas after : #23821
  • Experimental: Match if sub cases #23786

Capture checking and explicit nulls additions to the standard library are available only under -language:experimental.captureChecking / -Yexplicit-nulls respectively, or other means enabling these features.
These changes would not affect users who are not using any of these features.
Be aware that when inspecting sources, Scala Standard Library sources, as support for their syntax, might not be yet fully supported by the IDE of your choice.

Tooling

Changes to how the Scala Standard Library is published do, however, affect tooling, and upgrading to the latest versions is recommended.

Lazy Vals and JDK 24+ support

Scala 3.8 changes the implementation of Lazy Vals to make it compatible with JDK 25+.
Starting with Scala 3.0, the runtime required sun.misc.Unsafe to implement lazy vals; however, access to this functionality emits warnings starting with JDK 24 and is expected to throw exceptions in JDK 26 or later versions.

Scala 3.8.0 introduces a new implementation that is free of this problem by using java.lang.invoke.VarHandle instead. It’s also going to be backported to Scala 3.3 LTS and used optionally under a dedicated flag.
However, all existing Scala 3 dependencies using lazy vals would still contain references to sun.misc.Unsafe and would trigger its deprecation mechanism.

We’re working on a dedicated tool that would be able to resolve this problem by post-processing existing bytecode to replace usages of sun.misc.Unsafe emitted by the compiler.

Next steps

We’ve already identified issues that need to be resolved before a stable release. The subsequent RC versions can be expected to be released in the following days.

The compiler codebase itself has switched into a feature freeze mode in preparation for Scala 3.9 LTS - no new language features would be accepted (development and improvement of existing features is allowed). It allows us to focus on fixing existing bugs in both tooling and compiler to ensure a smooth transition into the Scala 3.9 LTS. The freeze would be lifted with the start of the Scala 3.10 development cycle.

Effectively, Scala 3.9 LTS would contain the same feature set as Scala 3.8 (we reserve the right to promote preview features into stable ones, but no new experimental or preview features would be introduced). As a result, any codebase using Scala 3.8 should not require any additional changes to use Scala 3.9 LTS.

Stable release

Stable release 3.8.0 would be published no earlier than 18th December; however, we reserve the right to delay the release in case of critical issues.

20 Likes

wow!Cannot wait to use the stable version! Not sure if we can see it before this Christmas.

1 Like

Wow, welcome to Scala community.

Just curious: why do we have no SIP-71 in List of All SIPs | Scala Documentation ?

I’m not sure about the current process and why it’s missing. I’ll rise this issue to responsible people.

All SIPs (including drafts) can be found at Pull requests Ā· scala/improvement-proposals Ā· GitHub as workaround

The SIP page has been broken for a very long time. I plan to fix it, but it might take a while.

The above repository is the current source of truth. Its main branch has the list of completed SIPs, and the PR queue lists the ones currently in progress.

1 Like

Hi! I’m trying to use relaxed lambdas. Can someone explain me, what’s the reason of the difference between these two definitions? Why the first one fails with value toMap is not a member of (Int, Int)?

val list = List(1, 2, 3)
val one = list
      .collect: case x => (x, x + 1)
      .toMap

val two = list
      .collect: x => (x, x + 1)
      .toMap

Most likely a bug in implementation of the feature in parser, currently compiler parsed and typed it as follows:

scala compile -S 3.8.0-RC1 test.scala -Vprint:typer
Compiling project (Scala 3.8.0-RC1, JVM (21))
[error] ./test.scala:6:29
[error] value toMap is not a member of (Int, Int)
[[syntax trees at end of                     typer]] // test.scala
package <empty> {
  import scala.language.experimental.relaxedLambdaSyntax
  final lazy module val test$package: test$package = new test$package()
  final module class test$package() extends Object() {
    this: test$package.type =>
    @main def Test: Unit =
      {
        val list: List[Int] = List.apply[Int]([1,2,3 : Int]*)
        val one: List[Nothing] =
          list.collect[Nothing]((x$1: Int) =>
            x$1 match 
              {
                case x @ _ => Tuple2.apply[Int, Int](x, x + 1).toMap
              }
          )
        val two: Map[Int, Int] =
          list.collect[(Int, Int)]((x: Int) => Tuple2.apply[Int, Int](x, x + 1))
            .toMap[Int, Int](<:<.refl[(Int, Int)])
        ()
      }
  }
}

Here’s a created issue Invalid parsing of partial function under `relaxedLambdaSyntax` Ā· Issue #24496 Ā· scala/scala3 Ā· GitHub to track it

  val four = list
        .collect: case
      x =>
    (x, x + 1)

case is just very relaxed.

I’m getting caught up. TIL SIP-less ā€œMatch if sub casesā€.

The release has so many good features, the highlights are tl;dr.

I do think a working SIPs page would be helpful. I used to consult it with some frequency, but now that I know it is stale, I will take it easy.

Edit: this works, I assume by establishing an ident after the = to outdent from.

import scala.language.experimental.relaxedLambdaSyntax

@main def Test =
  val list = List(1, 2, 3)

  val four =
             list
               .collect: case x => (x, x + 1)
           .toMap

  println:
    four

This warns about the misleading indentation:

  val four =
             list
               .collect: case x =>
             (x, x + 1)
           .toMap

Edit: Is this the equivalent of ā€œprompt engineeringā€ for significant indentation?

1 Like

Scala 3.8.0-RC2 is now available

This version added fixes to found regressions and improvements that have not made it before the RC1 cutoff, it includes:

  • JDK 26 support
  • Bump of Scala CLI to 1.10.1
  • Deprecated aliases would now warn, e.g. when using -Xfatal-warnings instead of -Werror

We’ve already identified some critical regressions, which would require another RC version, but still encourage users to try this version out and report their feedback

3 Likes

@WojciechMazur two questions:

  1. What defines the library versions in the community-build? Is it not the latest releases?
    I’m asking because my library (dfianthdl) shows up as failing in version v0.14.0 under Scala 3.8.x, but I released v0.16.0 to fix the issues I found.
  2. Is it still possible to get SIP-77 reviewed and implemented as experimental in 3.8? Implement SIP-77: Method Block End Markers by soronpo Ā· Pull Request #24251 Ā· scala/scala3 Ā· GitHub

The source of truth is Scaladex (index.scala-lang.org) and tags in the git repo. I’ve seen v0.16.0 was released 10 days. Due to some last infrastructure problems, and some changes in the build itself it was not synchronized for the 2 weeks. It should peek the latest version v0.16.0 for the next tested build (I’ll schedule run for 3.8.0-RC2 later today after synchronization of project versions)

Is it still possible to get SIP-77 reviewed and implemented as experimental in 3.8?

I don’t think that would be possible. 3.8 is already packed with changes, already behind the schedule (one of the reasons for previously unplanned 3.7.4 release), and with know regressions that needs to fixed as soon as possible. The PR might get approved, but it likely would not be merged until we start work on Scala 3.10 (so potentially March/April 2026 if we’d stick to schedule).
At this point it requires a strong argumentation to be included and approved by Core team (one other experimental feature was already discussed and was rejected)

I have a question, Pekko and Akka are not prepared with Scala 3.8 and compile with Scala 3.3.x, how can the community-build help here?

No need to worry about that. Currently for ~310 projects we use semi-automatic migrations using -source:3.x-migration, -rewrite which is enough to adopt Scala 3.3 (or even 3.0) source code to. latest nightlies. Sometimes we add additional simple patches if these are not covered by the rewrites (yet).
Since Open Community Build is based on entries from Scaladex we cannot test open-source projects not listed in this service. Potentially additional code bases can be added in this config file - adding some large/non-trivial project using Pekko/Akka might help.
The Akka/Pekko itself is affect by regression but it would be fixed before 3.8.0 stable. With just semi-automatic migrations it’s enough to ensure it build correctly under 3.7.4. It also tests all open-source users of these projects (mostly other libraries).

1 Like

I’m getting a regression in generic lambdas that return unit–I haven’t tested widely to see if it’s inline only or what, but the offending test in my test suite is

    val m = Mu(0)
    T ~ Resource(m)(_.zap(_ + 1)){ x => x := 2; x() + 2 } ==== 4

which tests resource closing vs. usage order, with

object Resource:
  def apply[R, A](rsc: Tidy[R] ?=> R)(done: Tidy[R])(f: R => A): A =
    val r = rsc(using done)
    try f(r)
    finally done(r)

trait Tidy[-T] extends (T => Unit):
  def apply(t: T): Unit

extension [A, M <: Mu[A]](mu: M)
  inline def zap(inline f: A => A): Unit = 
    inline mu match
      // It's complicated....

and fails with

[217] Test kse.test.flow.FlowTest.resourceTest failed: java.lang.BootstrapMethodError: bootstrap method initialization exception, took 0.002 sec
[217]     at java.lang.invoke.BootstrapMethodInvoker.invoke(BootstrapMethodInvoker.java:188)
[217]     at java.lang.invoke.CallSite.makeSite(CallSite.java:310)
[217]     at java.lang.invoke.MethodHandleNatives.linkCallSiteImpl(MethodHandleNatives.java:249)
[217]     at java.lang.invoke.MethodHandleNatives.linkCallSite(MethodHandleNatives.java:239)
[217]     at kse.test.flow.FlowTest.resourceTest$$anonfun$1(FlowTest.scala:2251)
[217]     at kse.testutilities.TestUtilities$Labeled.$anonfun$1(TestUtilities.scala:102)
[217]     at scala.util.Try$.apply(Try.scala:218)
[217]     at kse.testutilities.TestUtilities$Labeled.isEqual(TestUtilities.scala:102)
[217]     at kse.testutilities.TestUtilities$Labeled.$eq$eq$eq$eq(TestUtilities.scala:126)
[217]     at kse.test.flow.FlowTest.resourceTest(FlowTest.scala:2251)
[217]     ...
[217] Caused by: java.lang.invoke.LambdaConversionException: Type mismatch for lambda expected return: void is not convertible to class java.lang.Object
[217]     at java.lang.invoke.AbstractValidatingLambdaMetafactory.checkDescriptor(AbstractValidatingLambdaMetafactory.java:336)


If this is a known issue (improper / changed handling of unit return, probably with SAM, possibly interacting with inline) then I won’t dig farther. If it hasn’t come up elsewhere, then I’ll find a minimal reproduction.
(The key part of the error being: Type mismatch for lambda expected return: void is not convertible to class java.lang.Object)

1 Like

Thank you for reporting this issue. I’m able to reproduce it and would to further minimize it. I think there 1 potentially similar issue, but we’d confirm it later.

Problems like that could have slipped through, because by default OpenCB does not execute tests, but rather only ensure these can be compiled (due to flakiness, and lots of projects that require additional infra). We’ll run a dedicated build with tests enabled to check if more issues like the one in kse3 can be found

Okay, here it is very minimized–it’s an issue with SAM fulfillment when the trait extends a Function1 that returns Unit:

//> using scala 3.8.0-RC2

package minimized.bug_380RC2_kse3

trait Con[-T] extends (T => Unit):
  def apply(t: T): Unit

object Main:
  def main(args: Array[String]): Unit =
    val c: Con[Int] = i => println(i)
    c(2)

That’s fully runnable with scala-cli. The exception is on c(2)

If there’s no other issue that contains this, I can submit a new one. Otherwise, append it or merge it with whatever else is there.

(Note–it doesn’t matter whether the trait is contravariant or invariant; you get the same error either way. And it doesn’t have to be parameterized–trait Bug extends (Int => Unit) fails the same way. But it does have to have apply as the abstract method.)

Edit: it was also present in 3.8.0-RC1, and not in 3.7.2; I haven’t bisected more than that.

1 Like

Starting with 3.8.0-RC2 MiMa hangs forever when running mimaReportBinaryIssues for the Play Framework.

Reproducer (just checkout the latest_scala3 branch):

git clone -b latest_scala3 [email protected]:playframework/playframework.git
cd playframework/
sbt "++3.x; clean; mimaReportBinaryIssues"

...
[info] welcome to sbt 1.11.7 (Eclipse Adoptium Java 17.0.17)
...

I need to kill java process.

With Scala 3.7.4 the mimaReportBinaryIssues still works:

grep -rl '3.8.0-RC2' | xargs sed -i 's/3.8.0-RC2/3.7.4/g'

There is an similiar (or same?) issue in the MiMa repo already: Deadlock in Scala 3 version of MiMa when analyzing scala 3 code Ā· Issue #867 Ā· lightbend-labs/mima Ā· GitHub Not sure if our problem is the same.

Thanks!

Edit: Also tried the current MiMa main branch (336b8b1) locally without success.

I was wrong. It has nothing to do with MiMa, things also hang when compiling: sbt "++3.x; clean; compile" (Our CI pipeline starts with mima and the mima issue referenced above made me think this is a mima problem before I even tried to compile).

You can see the CI jobs hanging here: Make Play compatible with latest Scala Ā· playframework/playframework@4b99960 Ā· GitHub
But same happens locally on my Linux machine.

Edit: I don’t think it matters but just so you know:

$ cat .sbtopts 
-J-Xms2G
-J-Xmx2G
-J-Xss2M
-J-XX:MaxInlineLevel=18
-J-XX:MaxMetaspaceSize=1G
-J-Dfile.encoding=UTF-8

The slow compilation was fixed in latest nightly (3.8.1-RC1-bin-20251128-fe49539-NIGHTLY) it would be backported to RC3, what remains for the Play is the same issue as in the Akka/Pekko projects We’re working on the fix for that.

4 Likes