Skip to content

Add Scala 3.6.2 announcement #1699

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

Merged
merged 15 commits into from
Dec 10, 2024
Merged
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,16 +1,26 @@
---
category: announcement
permalink: /news/3.6.0
title: "Scala 3.6.0 is now available!"
permalink: /news/3.6.2
title: "Scala 3.6.2 is now available!"
---

![Scala 3.6]({{ site.baseurl }}/resources/img/scala-3.6-launch.jpg)

We're happy to announce the next minor release of Scala - 3.6.0 is finally out!
We're happy to announce the next minor release of Scala - 3.6.2 is finally out!

# What’s new in 3.6.0?
# What happend to Scala 3.6.0 and 3.6.1?

Besides multiple bugfixes, this release stabilises multiple experimental features introduced to Scala language after careful review and acceptance by the [Scala Improvement Proposal's Commitee](https://docs.scala-lang.org/sips/). Many of these changes can have a significant impact on the Scala syntax and are introducing new amazing possibilities in writing concise, typesafe as well as easier, and easier to maintain code.
During the release of 3.6.0-RC1, an accident caused the publishing of artefacts versioned as 3.6.0 to the immutable Maven repository.
To mitigate possible damage we've released a hotfix release 3.6.1 to prevent automatic tooling from using a broken version of the compiler.
Versions 3.6.0 (a broken release) and 3.6.1 (a hotfix release) should never be used.
The incident was described in detail at [Scala 3.6.0 Post Mortem blogpost](https://www.scala-lang.org/news/post-mortem-3.6.0.html).

Scala 3.6.2 should effectively be regarded as "3.6.0" for all intents and purposes.
We apologize to the Scala users for any inconvenience it might have caused.

# What’s new in Scala 3.6?

Besides multiple bugfixes, this release stabilises multiple experimental features introduced to Scala language after careful review and acceptance by the [Scala Improvement Proposal's Commitee](https://docs.scala-lang.org/sips/). Many of these changes can have a significant impact on the Scala syntax and are introducing new possibilities in writing concise, typesafe as well as easier, and easier to maintain code.

## SIP-47 - Clause Interleaving

Expand All @@ -24,71 +34,6 @@ trait DB {
}
```

## SIP-58 - Named Tuples

Another stabilized feature in this release are the Named Tuples. These have been introduced as experimental in Scala 3.5.0 and allowed you to give meaningful names to tuple elements and use those names during constructing, destructuring, and pattern matching.

```scala
extension [T](seq: Seq[T])
def partitionBy(predicate: PartialFunction[T, Boolean]): (matching: Seq[T], unmatched: Seq[T]) =
seq.partition(predicate.unapply(_).isDefined)

@main def onlySmallRealNumbers =
List(
(x = 1, y = 0),
(x = 2, y = 3),
(x = 0, y = 1),
(x = 3, y = 0),
).partitionBy:
case (x = real, y = 0) => real < 5
.matching.map(_.x)
.foreach(println)
```

This change also introduces improvements to extractors of case classes. You can now define named extractors for a selection of fields, allowing you to unclutter your code from unused variables.

```scala
case class User(id: Int, name: String, surname: String)

extension (values: Seq[User])
// Collect user IDs of every entry that has the name matching argument
def idsWithName(name: String) = values.collect:
case User(name = `name`, id = userId) => userId
```

Last, but not least, named tuples are opening a new paradigm of metaprogramming by letting you compute structural types without need for macros!
The `Selectable` trait now has a `Fields` type member that can be instantiated to a named tuple.

```scala
class QueryResult[T](rawValues: Map[String, Any]) extends Selectable:
type Fields = NamedTuple.Map[NamedTuple.From[T], Option]
def selectDynamic(fieldName: String) = rawValues.get(fieldName)

case class City(zipCode: Int, name: String)

@main def Test =
val query: QueryResult[City] = QueryResult(Map("name" -> "Lausanne"))
assert(query.name.contains("Lausanne"))
assert(query.zipCode.isEmpty)
```

You can read more about named tuples in the [dedicated section of Scala 3 reference documentation](https://scala-lang.org/api/3.6.0/docs/docs/reference/other-new-features/named-tuples.html).

## SIP-62 - For-Comprehension Improvements

Starting with Scala 3.6.0 you can take advantage of improvements to the for-comprehesnions syntax.
Major user-facing improvement introduced by [SIP-62](https://docs.scala-lang.org/sips/better-fors.html) is the ability to start a for-comprehension block with aliases:

```scala
for
a = 1
b <- Some(2)
c <- doSth(a)
yield b + c
```

It also introduces changes to how your code is desugared by the compiler, leading to a more optimized code by removing some redundant calls.

## SIP-64 - Improve Syntax for Context Bounds and Givens

This release stabilises the [SIP-64](https://docs.scala-lang.org/sips/sips/typeclasses-syntax.html) introduced as experimental in Scala 3.5.0. These changes provide you with the new syntax for defining type class instances.
Expand Down Expand Up @@ -147,13 +92,13 @@ class Set[T] extends Collection:
override given Order[Element] = ??? // custom implementation provided by the user
```

See the updated [Contextual Abstractions](https://scala-lang.org/api/3.6.0/docs/docs/reference/contextual/givens.html) chapter of the Scala 3 reference guide to learn more about these changes.
See the updated [Contextual Abstractions](https://scala-lang.org/api/3.6.2/docs/docs/reference/contextual/givens.html) chapter of the Scala 3 reference guide to learn more about these changes.

_**Note**: It is important not to confuse changes under SIP-64 with the [experimental modularity improvements](https://dotty.epfl.ch/docs/reference/experimental/typeclasses.html) available under `-language:experimental.modularity` and `-source:future`. These changes are still being developed in the experimental phase and would require SIP committee acceptance before stabilisation.

## SIP-56 Amendment: Match types extractors follow aliases and singletons

Scala 3.6.0 also stabilises the improvements of match types previously available under `-language:experimental.betterMatchTypeExtractors`. These changes were amending the match type specification and adjusting the implementation of match types under [SIP-56](https://docs.scala-lang.org/sips/match-types-spec.html) to resolve some of the issues reported by users. Under the new rules, it is possible to correctly resolve aliases and singleton types.
Scala 3.6 also stabilises the improvements of match types previously available under `-language:experimental.betterMatchTypeExtractors`. These changes were amending the match type specification and adjusting the implementation of match types under [SIP-56](https://docs.scala-lang.org/sips/match-types-spec.html) to resolve some of the issues reported by users. Under the new rules, it is possible to correctly resolve aliases and singleton types.

```scala
trait A:
Expand All @@ -170,6 +115,23 @@ type InvF[Y] = Y match
def Test = summon[InvF[B] =:= String] // was error: selector B does not uniquely determine parameter x
```

## Experimental SIP-62 - For-Comprehension Improvements

Starting with Scala 3.6.2 you can take advantage of improvements to the for-comprehesnions syntax.
Major user-facing improvement introduced by [SIP-62](https://docs.scala-lang.org/sips/better-fors.html) is the ability to start a for-comprehension block with aliases:

```scala
//> using options -experimental -language:experimental.betterFors
@main def betterFors =
for
a = 1
b <- Some(2)
c <- Option.when(a < 5)(10)
yield b * c
```

It also introduces changes to how your code is desugared by the compiler, leading to a more optimized code by removing some redundant calls.

## Experimental SIP-57 - Replace non-sensical `@unchecked` annotations

One of the new, experimental, features is the implementation of [SIP-57](https://docs.scala-lang.org/sips/replace-nonsensical-unchecked-annotation.html) introducing a `runtimeChecked` extension method replacing some usages of `@unchecked` annotation using a more convenient syntax. A common use case for `runtimeChecked` is to assert that a pattern will always match, either for convenience or because there is a known invariant that the types can not express.
Expand All @@ -188,7 +150,7 @@ val Some(appVersion) = config.get("appVersion").runtimeChecked

## Switch mapping of context bounds to using clauses

Until Scala 3.6.0 context bound parameters were always desugared to `implicit` arguments, starting with 3.6.0 these would be mapped to `using` parameters instead.
Until Scala 3.6 context bound parameters were always desugared to `implicit` arguments, starting with Scala 3.6 these would be mapped to `using` parameters instead.
This change should not affect the majority of users, however, it can lead to differences in how implicits are resolved.
Resolution of implicits can slightly differ depending on whether we're requesting them using `implicit` or `using` parameter, or depending on whether they were defined using `implicit` or `given` keywords. The special behaviours were introduced to smoothen migration from Scala 2 to brand new implicits resolution in Scala 3.
This change might also affect some of the projects that use compiler plugins or macros to inspect the implicit argument lists of the function calls - these might require some minor fixes, eg. when filtering symbols by their flags.
Expand All @@ -199,7 +161,7 @@ This change might also affect some of the projects that use compiler plugins or

In the [Scala 3.5.0 release notes](https://scala-lang.org/blog/2024/08/22/scala-3.5.0-released.html) we've announced upcoming changes to givens, due to their peculiar problem with prioritization. Currently, the compiler always tries to select the instance with the most specific subtype of the requested type. In the future, it would change to always selecting the instance with the most general subtype that satisfies the context-bound.

Starting from Scala 3.6.0, code whose behaviour can differ between new and old rules (ambiguity on new, passing on old, or vice versa) will emit warnings, but the old rules will still be applied.
Starting from Scala 3.6, code whose behaviour can differ between new and old rules (ambiguity on new, passing on old, or vice versa) will emit warnings, but the old rules will still be applied.
Running the compiler with `-source:3.5` will allow you to temporarily keep using the old rules; with `-source:3.7` or `-source:future` the new scheme will be used.

For the detailed motivation of changes with examples of code that will be easier to write and understand, see our recent blog post - [Upcoming Changes to Givens in Scala 3.7]({{ site.baseurl }}/2024/08/19/given-priority-change-3.7.html).
Expand All @@ -217,16 +179,76 @@ Let's take the following example:
```

Reordering the fields is binary-compatible but it might affect the meaning of `@Annotation(1)`
Starting from Scala 3.6.0, named arguments are required for Java-defined annotations.
Starting from Scala 3.6, named arguments are required for Java-defined annotations.
The compiler can provide you with automatic rewrites introducing now required names, using `-source:3.6-migration, -rewrite` flags. The rewrites are done on a best-effort basis and should be inspected for correctness by the users.

## Experimental SIP-58 - Named Tuples

Named Tuples have been introduced as experimental in Scala 3.5.0. This feature is now ready to be tested, but is not yet stablized.
We encourage you to try named tuples and to report your feedback [on the public forum](https://contributors.scala-lang.org/t/pre-sip-named-tuples).
Named Tuples allow you to give meaningful names to tuple elements and use those names during constructing, destructuring, and pattern matching.

```scala
//> using options -experimental -language:experimental.namedTuples
extension [T](seq: Seq[T])
def partitionBy(predicate: PartialFunction[T, Boolean]): (matching: Seq[T], unmatched: Seq[T]) =
seq.partition(predicate.unapply(_).isDefined)

@main def onlySmallRealNumbers =
List(
(x = 1, y = 0),
(x = 2, y = 3),
(x = 0, y = 1),
(x = 3, y = 0),
).partitionBy:
case (x = real, y = 0) => real < 5
.matching.map(_.x)
.foreach(println)
```

This change also introduces improvements to extractors of case classes. You can now define named extractors for a selection of fields, allowing you to unclutter your code from unused variables.

```scala
//> using options -experimental -language:experimental.namedTuples
case class User(id: Int, name: String, surname: String)

extension (values: Seq[User])
// Collect user IDs of every entry that has the name matching argument
def idsWithName(name: String) = values.collect:
case User(name = `name`, id = userId) => userId
```

Last, but not least, named tuples are opening a new paradigm of metaprogramming by letting you compute structural types without need for macros!
The `Selectable` trait now has a `Fields` type member that can be instantiated to a named tuple.

```scala
//> using options -experimental -language:experimental.namedTuples
class QueryResult[T](rawValues: Map[String, Any]) extends Selectable:
type Fields = NamedTuple.Map[NamedTuple.From[T], Option]
def selectDynamic(fieldName: String) = rawValues.get(fieldName)

case class City(zipCode: Int, name: String)

@main def Test =
val query: QueryResult[City] = QueryResult(Map("name" -> "Lausanne"))
assert(query.name.contains("Lausanne"))
assert(query.zipCode.isEmpty)
```

You can read more about named tuples in the [dedicated section of Scala 3 reference documentation](https://scala-lang.org/api/3.6.2/docs/docs/reference/experimental/named-tuples.html).

# What’s next?
<!-- TODO: Fill me -->

The Scala 3.6.2 will be followed by at least 2 patch releases, during which we will focus on bug fixes and improvements to experimental features based on your feedback.
You can expect Scala 3.6.3 to be released in the middle of January followed by 3.6.4 by the end of Q1 2025.
In Q2 2025 we're planning a new minor release of Scala 3.7 that might bring stabilisation to some of the experimental features. We are encouraging you to test out the experimental features mentioned in this article and share your feedback with the Scala team.

Currently, we are also preparing a Scala 3.3.5 LTS patch release - it would include all backportable changes introduced until Scala 3.5.2. It should be released in January 2025.

# Contributors

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

According to git shortlog -sn --no-merges 3.5.2..3.6.0 these are:
According to git shortlog -sn --no-merges 3.5.2..3.6.2 these are:

<!-- TODO: Fill me -->