Skip to content

Commit

Permalink
Further edits on the announcement:
Browse files Browse the repository at this point in the history
- add contributors list
- add named tuples section
- shorten the given prioritazation section
  • Loading branch information
Kordyjan committed Aug 16, 2024
1 parent 7f0fd24 commit 7e5f614
Showing 1 changed file with 62 additions and 22 deletions.
84 changes: 62 additions & 22 deletions blog/_posts/2024-10-15-scala-3.5.0-released.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,37 +76,32 @@ assert(0B_1000_0010 == 130)
assert(0B_1000_0010 == 0x82)
```

## Work on a better scheme for given prioritization
### Experimental: named tuples

Givens in Scala 3 have a peculiar problem with prioritization. To illustrate it, let's consider the following inheritance triangle for type classes:
Scala 3.5 introduces experimental support for named tuples. The feature hidden behind the `language.experimental.namedTuples` import, allows you to give meaningful names to tuple elements and use those nemes during constructing, destructuring, and pattern matching.

```scala
trait Functor[F[_]]:
extension [A, B](x: F[A]) def map(f: A => B): F[B]
trait Monad[F[_]] extends Functor[F] { ... }
trait Traverse[F[_]] extends Functor[F] { ... }
```

and corresponding instances
import scala.language.experimental.namedTuples

```scala
given Functor[List] = ???
given Monad[List] = ???
given Traverse[List] = ???
```
type Point = (x: Int, y: Int)
val point: Point = (x = 1, y = 2)
val is_it_point = (x = 5, y = 3)
val it_is: Point = is_it_point

Now, let's use the instances in the following context:
println(point.x) // prints 1

```scala
def fmap[F[_] : Functor, A, B](c: F[A])(f: A => B): F[B] = c.map(f)
fmap(List(1,2,3))(_.toString) // ERROR
point match
case (x = real, y = 0) => println(s"Real number: $real")
case _ => println("Point doesn't represent a real number")
```

The compiler will reject the above code with a message about the `Functor` context bound being ambiguous. This is unintuitive and undesired behavior. The reason for this is that `Monad` and `Traverse` types are subtypes of `Functor`, so their instances are more specific than the `Functor` instance. They, in turn, are incomparable in terms of specificity, so the result is ambiguity.
This is an implementation of [SIP-58](https://github.com/scala/improvement-proposals/blob/d649f6e6f333cd9232d85a12bd0445d18a673f10/content/named-tuples.md).

The solution to this kind of problem is to change the scheme of given prioritization. If we decide that we are always selecting the instance with **the most general subtype** that satisfies the context bound, the above example would work as intended.
## Work on a better scheme for given prioritization

Givens in Scala 3 have a peculiar problem with prioritization. The compiler tries to always select the instance with *the most specific subtype* of the requested type. This can lead to confusing situtaions, when user faces ambiguity errors in code that should intuitivel work. Changing the scheme of given priritization to always select the instance with *the most general subtype* that satisfies the context bound, would resolve such cases. We have conducted experiments that showed that the proposed scheme will result in a more intuitive and predictable given resolution. The negative impact on the existing projects is very small. We have tested 1500 open-source libraries, and new rules are causing problems for less than a dozen of them. We have already submitted PRs with changes that will make them work the same way under both the current and proposed rules.

We have conducted experiments that showed that the proposed scheme will result in a more intuitive and predictable given resolution. The negative impact on the existing projects is very small. We have tested 1500 open-source libraries, and new rules are causing problems for less than a dozen of them. We have already submitted PRs with changes that will make them work the same way under both the current and proposed rules.
For the detailed motivation of changes with examples of code that will be easier to write and understand, see our recent blogpost //// TODO LINK

Our current plan is to introduce the new scheme in Scala 3.7. Starting from Scala 3.6, code whose behavior 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. 3.5 gives you a chance to detect if those changes affect your codebase. Running the compiler with `-source 3.6` will give you warnings; with `-source 3.7` or `-source future` you will get the new scheme.

Expand All @@ -116,4 +111,49 @@ There is already 3.5.1-RC1 published on Maven Central. This release contains mul

## Contributors

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

According to `git shortlog -sn --no-merges 3.4.2..3.5.0` these are:

```
153 Martin Odersky
53 Eugene Flesselle
41 Jamie Thompson
29 Wojciech Mazur
25 Nicolas Stucki
22 Sébastien Doeraene
18 noti0na1
16 Matt Bovel
13 Guillaume Martres
11 Paweł Marks
10 Hamza REMMAL
9 Yichen Xu
8 Jan Chyb
7 Hamza Remmal
7 Som Snytt
6 Jędrzej Rochala
5 Fengyun Liu
5 dependabot[bot]
3 Mikołaj Fornal
2 Aviv Keller
2 EnzeXing
1 Chris Pado
1 Filip Zybała
1 Georgi Krastev
1 Jisoo Park
1 Katarzyna Marek
1 Lucas Nouguier
1 Lucy Martin
1 Ola Flisbäck
1 Pascal Weisenburger
1 Quentin Bernet
1 Raphael Jolly
1 Seth Tisue
1 Stephane Bersier
1 Tomasz Godzik
1 Yoonjae Jeon
1 aherlihy
1 rochala
1 willerf
```

0 comments on commit 7e5f614

Please sign in to comment.