Skip to content

Commit 86b911a

Browse files
Add Scala 3.6.2 announcement (#1699)
1 parent 77abb98 commit 86b911a

File tree

2 files changed

+344
-0
lines changed

2 files changed

+344
-0
lines changed
Lines changed: 344 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,344 @@
1+
---
2+
category: announcement
3+
permalink: /news/3.6.2
4+
title: "Scala 3.6.2 is now available!"
5+
---
6+
7+
![Scala 3.6]({{ site.baseurl }}/resources/img/scala-3.6-launch.jpg)
8+
9+
We're happy to announce the next minor release of Scala - 3.6.2 is finally out!
10+
11+
# What happened to Scala 3.6.0 and 3.6.1?
12+
13+
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.
14+
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.
15+
Versions 3.6.0 (a broken release) and 3.6.1 (a hotfix release) should never be used.
16+
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).
17+
18+
Scala 3.6.2 should effectively be regarded as "3.6.0" for all intents and purposes.
19+
We apologize to the Scala users for any inconvenience it might have caused.
20+
21+
# What’s new in Scala 3.6?
22+
23+
Besides multiple bugfixes, this release stabilises multiple experimental features introduced to the 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.
24+
25+
## SIP-47 - Clause Interleaving
26+
27+
The first major feature we're going to cover is the [clause interleaving](https://docs.scala-lang.org/sips/clause-interleaving.html).
28+
With this change to the language, you're able to define multiple type parameter lists or place them after the first arguments list. Clause interleaving would benefit the path-dependent API creators.
29+
30+
```scala
31+
trait Key { type Value }
32+
trait DB {
33+
def getOrElse(k: Key)[V >: k.Value](default: V): V // dependent type parameter
34+
}
35+
```
36+
37+
## SIP-64 - Improve Syntax for Context Bounds and Givens
38+
39+
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.
40+
The goal of these changes is to simplify and narrow the syntax rules required to create a given instance. To name a few:
41+
42+
- you can now replace the `with` keyword with `:` when defining simple type classes,
43+
- context bounds can now be named and aggregated using `T : {A, B}` syntax,
44+
- conditional givens can also be defined with parameters
45+
- by-name givens can be defined using conditional given with empty parameters list
46+
47+
```scala
48+
trait Order[T]:
49+
extension (values: Seq[T]) def toSorted: Seq[T] = ???
50+
def compare(x: T, y: T): Int
51+
52+
// No need for `with` keyword
53+
given Order[Int]:
54+
def compare(x: Int, y: Int): Int = ???
55+
56+
// Named given instance using named context bound parameter
57+
given listOrdering: [T: Order as elementOrder] => Order[List[T]]:
58+
def compare(x: List[T], y: List[T]): Int = elementOrder.compare(x.head, y.head)
59+
60+
trait Show[T]:
61+
extension (value: T) def asString: String
62+
63+
// Aggregated context parameters
64+
def showOrdered[T: {Order as unusedName, Show}](values: Seq[T]): Unit =
65+
values.toSorted.map(_.asString).foreach(println)
66+
67+
// Conditional givens where a contextual instance of Config is required to create an instance of Factory
68+
trait Config
69+
trait Factory
70+
class MemoizingFactory(config: Config) extends Factory
71+
given (config: Config) => Factory = MemoizingFactory(config)
72+
73+
// By-name given
74+
trait Context
75+
given context: () => Context = ???
76+
```
77+
78+
Other changes to type classes involve the stabilisation of context bounds for type members.
79+
This mechanism allows defining an abstract given instance that needs to be provided by a class implementing the trait that defines an abstract given.
80+
81+
```scala
82+
trait Order[T]
83+
trait Show[T]
84+
85+
trait Collection:
86+
// abstract member context-bound
87+
type Element: Order
88+
// explicit abstract given
89+
given Show[Element] = compiletime.deferred
90+
91+
class List[T: {Order, Show}] extends Collection:
92+
type Element = T
93+
// generated by compiler, uses class context bound
94+
// override final given Order[Element] = evidence$1
95+
// override final given Show[Element] = evidence$2
96+
97+
class Set[T: Show as show] extends Collection:
98+
type Element = T
99+
override given Order[Element] = ??? // custom implementation provided by the user
100+
// override final given Show[Element] = this.show // generated by compiler
101+
```
102+
103+
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.
104+
105+
_**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.
106+
107+
## SIP-56 Amendment: Match types extractors follow aliases and singletons
108+
109+
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.
110+
111+
```scala
112+
trait A:
113+
type T
114+
type U = T
115+
116+
trait B extends A:
117+
type T = String
118+
119+
type F[X] = A { type U = X }
120+
type InvF[Y] = Y match
121+
case F[x] => x
122+
123+
def Test = summon[InvF[B] =:= String] // was error: selector B does not uniquely determine parameter x
124+
```
125+
126+
## Experimental SIP-62 - For-Comprehension Improvements
127+
128+
Starting with Scala 3.6.2 you can take advantage of improvements to the for-comprehensions syntax.
129+
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:
130+
131+
```scala
132+
//> using options -experimental -language:experimental.betterFors
133+
@main def betterFors =
134+
for
135+
a = 1
136+
b <- Some(2)
137+
c <- Option.when(a < 5)(10)
138+
yield b * c
139+
```
140+
141+
It also introduces changes to how your code is desugared by the compiler, leading to a more optimized code by removing some redundant calls.
142+
143+
## Experimental SIP-57 - Replace non-sensical `@unchecked` annotations
144+
145+
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.
146+
147+
Some typical use cases might be looking up an expected entry in a dynamically loaded dictionary-like structure:
148+
149+
```scala
150+
//> using options -experimental
151+
trait AppConfig:
152+
def get(key: String): Option[String]
153+
val config: AppConfig = ???
154+
155+
val Some(appVersion) = config.get("appVersion").runtimeChecked
156+
```
157+
158+
# Other notable changes
159+
160+
## Switch mapping of context bounds to using clauses
161+
162+
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.
163+
This change should not affect the majority of users, however, it can lead to differences in how implicits are resolved.
164+
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.
165+
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.
166+
167+
## Work on a better scheme for given prioritization
168+
169+
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.
170+
171+
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.
172+
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.
173+
174+
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).
175+
176+
## Require named arguments for Java-defined annotations
177+
178+
Java-defined annotations don't have an exact constructor representation. The compiler previously relied on the order of the fields to create annotation instance. One possible issue with this representation is the reordering of the fields.
179+
Let's take the following example:
180+
181+
```scala
182+
public @interface Annotation {
183+
int a() default 41;
184+
int b() default 42;
185+
}
186+
```
187+
188+
Reordering the fields is binary-compatible but it might affect the meaning of `@Annotation(1)`
189+
Starting from Scala 3.6, named arguments are required for Java-defined annotations that define multiple parameters.
190+
If the Java-defined annotation contains paramter named `value` its name can be ommited only when annotation is applied using a single argument.
191+
192+
```Java
193+
public @interface Example {
194+
String value() default "";
195+
String param() default "";
196+
}
197+
public @interface NoValueExample {
198+
String param() default "";
199+
}
200+
```
201+
202+
```Scala
203+
// Annotation with `value: String = "", param: String = ""` paramters
204+
@Example()
205+
def onlyDefaults: Unit = ()
206+
207+
@Example("param")
208+
def valueWithDefaults: Unit = ()
209+
210+
@Example(value = "ok", param = "fine")
211+
def multipleParams: Unit = ()
212+
213+
@Example("a", "b") // error, both parameters should be named
214+
def multipleUnnamedParams: Unit = ()
215+
216+
@Example("first", param = "second") // error, `"first"` argument should be named
217+
def multipleMixedParams: Unit = ()
218+
219+
// Annotation with `param: String = ""` parameters
220+
@NoValueExample()
221+
def defaultOnly: Unit = ()
222+
223+
@NoValueExample(param = "foo")
224+
def namedParam: Unit = ()
225+
226+
@NoValueExample("foo") // error, the only parameter is not named `value`
227+
def invalidUnnamedParam: Unit = ()
228+
```
229+
230+
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.
231+
232+
## Experimental SIP-58 - Named Tuples
233+
234+
Named Tuples have been introduced as experimental in Scala 3.5.0. This feature is now ready to be tested, but is not yet stabilized.
235+
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).
236+
Named Tuples allow you to give meaningful names to tuple elements and use those names during constructing, destructuring, and pattern matching.
237+
238+
```scala
239+
//> using options -experimental -language:experimental.namedTuples
240+
extension [T](seq: Seq[T])
241+
def partitionBy(predicate: PartialFunction[T, Boolean]): (matching: Seq[T], unmatched: Seq[T]) =
242+
seq.partition(predicate.unapply(_).isDefined)
243+
244+
@main def onlySmallRealNumbers =
245+
List(
246+
(x = 1, y = 0),
247+
(x = 2, y = 3),
248+
(x = 0, y = 1),
249+
(x = 3, y = 0),
250+
).partitionBy:
251+
case (x = real, y = 0) => real < 5
252+
.matching.map(_.x)
253+
.foreach(println)
254+
```
255+
256+
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.
257+
258+
```scala
259+
//> using options -experimental -language:experimental.namedTuples
260+
case class User(id: Int, name: String, surname: String)
261+
262+
extension (values: Seq[User])
263+
// Collect user IDs of every entry that has the name matching argument
264+
def idsWithName(name: String) = values.collect:
265+
case User(name = `name`, id = userId) => userId
266+
```
267+
268+
Last, but not least, named tuples are opening a new paradigm of metaprogramming by letting you compute structural types without need for macros!
269+
The `Selectable` trait now has a `Fields` type member that can be instantiated to a named tuple.
270+
271+
```scala
272+
//> using options -experimental -language:experimental.namedTuples
273+
class QueryResult[T](rawValues: Map[String, Any]) extends Selectable:
274+
type Fields = NamedTuple.Map[NamedTuple.From[T], Option]
275+
def selectDynamic(fieldName: String) = rawValues.get(fieldName)
276+
277+
case class City(zipCode: Int, name: String)
278+
279+
@main def Test =
280+
val query: QueryResult[City] = QueryResult(Map("name" -> "Lausanne"))
281+
assert(query.name.contains("Lausanne"))
282+
assert(query.zipCode.isEmpty)
283+
```
284+
285+
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).
286+
287+
# What’s next?
288+
289+
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.
290+
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.
291+
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.
292+
293+
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.
294+
295+
# Contributors
296+
297+
Thank you to all the contributors who made this release possible 🎉
298+
299+
According to `git shortlog -sn --no-merges 3.5.2..3.6.2` these are:
300+
301+
```
302+
128 Martin Odersky
303+
53 Wojciech Mazur
304+
44 Dale Wijnand
305+
35 Hamza REMMAL
306+
33 Kacper Korban
307+
31 Eugene Flesselle
308+
22 Hamza Remmal
309+
11 Katarzyna Marek
310+
10 Matt Bovel
311+
9 noti0na1
312+
9 rochala
313+
8 Jamie Thompson
314+
8 Jan Chyb
315+
7 Adrien Piquerez
316+
7 Som Snytt
317+
7 Sébastien Doeraene
318+
7 dependabot[bot]
319+
6 Yichen Xu
320+
5 EnzeXing
321+
5 Guillaume Martres
322+
4 Fengyun Liu
323+
4 kasiaMarek
324+
3 Martin Duhem
325+
3 Oliver Bracevac
326+
3 Piotr Chabelski
327+
2 Aleksander Rainko
328+
2 David Hua
329+
2 Florian3k
330+
2 HarrisL2
331+
2 Joel Wilsson
332+
2 Jędrzej Rochala
333+
2 Kenji Yoshida
334+
1 Eugene Yokota
335+
1 Kavin Satheeskumar
336+
1 Lorenzo Gabriele
337+
1 Michel Charpentier
338+
1 Ondrej Lhotak
339+
1 Raphael Jolly
340+
1 Tomasz Godzik
341+
1 Yuito Murase
342+
1 crunchyfrog
343+
1 philippus
344+
```

resources/img/scala-3.6-launch.jpg

190 KB
Loading

0 commit comments

Comments
 (0)