Skip to content

Commit f00e09c

Browse files
Add 22nd release article
1 parent b0aac8c commit f00e09c

File tree

1 file changed

+293
-0
lines changed

1 file changed

+293
-0
lines changed
Lines changed: 293 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,293 @@
1+
---
2+
layout: blog-page
3+
title: Announcing Dotty 0.22.0-RC1 - syntactic enhancements, type-level arithmetic and more
4+
author: Anatolii Kmetiuk
5+
authorImg: /images/anatolii.png
6+
date: 2020-02-05
7+
---
8+
9+
Hello! We are excited to announce 0.22.0-RC1 of Dotty. This version brings syntactic enhancements for extension methods and context parameters, as well as the kind projector syntax. Other notable changes include type-level arithmetic, changes to the `inline` parameters semantics and suggestions on missing context parameters.
10+
11+
You can try out this version right now, from the comfort of your SBT, by visiting the [home page](https://dotty.epfl.ch/) and scrolling down to the "Create a Dotty Project" section. Enjoy the ride🚀!
12+
13+
<!--more-->
14+
# New syntax for collective extension methods
15+
Extension methods have been present in Dotty for a while. They present an idiomatic way to extend types with methods after these types are defined. For example:
16+
17+
```scala
18+
def (x: Int) toPower (n: Int): Int =
19+
@annotation.tailrec def loop(accum: Int, power: Int): Int =
20+
if power == 0 then accum
21+
else if power > 0 then loop(accum * x, power - 1)
22+
else throw IllegalArgumentException("This operation only supports positive powers")
23+
loop(1, n)
24+
println(s"3^3 = ${3.toPower(3)}") // 3^3 = 27
25+
```
26+
27+
However, when one wants to define multiple extension methods for a type, a lot of boilerplate manifests:
28+
29+
```scala
30+
def (x: Int) toPower (n: Int): Int = ???
31+
def (x: Int) squared = ???
32+
def (x: Int) asBinaryString = ???
33+
```
34+
35+
The type in question and the name of its parameter, `(x: Int)`, repeat.
36+
37+
This boilerplate was the motivation to introduce collective extension methods. For a while, we were experimenting with looking at these through the lens of the `given` mechanism. We have tried out an idea of making these methods belong to an object visible in the `given` scope and, if such an object is present in the `given` scope, its extension methods are also automatically usable.
38+
39+
However, `given` instances are about *types* and the collective extension methods describe *parameters* of extension methods. Hence, in this release we introduce a new syntax for the collective extension methods:
40+
41+
```scala
42+
extension listOps on [T](xs: List[T]) {
43+
def second = xs.tail.head
44+
def third: T = xs.tail.tail.head
45+
}
46+
47+
val list = List(1, 2, 3)
48+
println(s"Second: ${list.second}") // 2
49+
println(s"Third: ${list.third}") // 3
50+
```
51+
52+
This syntax is a completely separate one from the `given` syntax and hence is aimed to bring more clarity and disentangle the two different concepts.
53+
54+
For the discussion, see [PR #7917](https://github.com/lampepfl/dotty/pull/7917). For more information on how to use extension methods in general and collective extension methods in particular, see the [documentation](https://dotty.epfl.ch/docs/reference/contextual/extension-methods.html).
55+
56+
# Kind projector syntax support
57+
[Kind projector](https://github.com/typelevel/kind-projector) is a popular compiler plugin for Scala 2. It is especially useful in the context of purely functional programming and typeclass derivation – everywhere where you need to work extensively with types.
58+
59+
As of this release, a subset of the kind projector syntax is now supported in Dotty. Credits for this contribution go to [Travis Brown](https://github.com/travisbrown).
60+
61+
To enable it, you need to run the compiler with the `-Ykind-projector` flag. You can e.g. write the following:
62+
63+
```scala
64+
// Fix #7139: Implement kind-projector compatibility #7775
65+
// With -Ykind-projector
66+
67+
trait Functor[F[_]]
68+
def map[A, B](fa: F[A], f: A => B): F[B]
69+
70+
object eitherFunctor extends Functor[Either[Int, *]]
71+
def map[A, B](fa: Either[Int, A], f: A => B): Either[Int, B] = fa match
72+
case Right(x) => Right(f(x))
73+
case Left(x) => Left(x)
74+
75+
object functionFunctor extends Functor[Int => *]
76+
def map[A, B](fa: Int => A, f: A => B): Int => B =
77+
fa andThen f
78+
79+
object tupleFunctor extends Functor[λ[x => (x, x)]]
80+
def map[A, B](fa: (A, A), f: A => B): (B, B) = fa match
81+
case (a1, a2) => (f(a1), f(a2))
82+
83+
@main def Test =
84+
val tpl = (1, 2)
85+
val squared = tupleFunctor.map(tpl, a => a * a)
86+
println(squared) // (1,4)
87+
```
88+
89+
For the discussion, see [PR #7775](https://github.com/lampepfl/dotty/pull/7775). Also see the GitHub [repository](https://github.com/typelevel/kind-projector) of the kind projector Scala 2 plugin for more context.
90+
91+
# Further improvements to the context parameters syntax
92+
Scala 3 context parameters are successors of Scala 2 implicits. In Scala 2, they proved useful for a wide range of applications including purely functional programming, dependency injection, type class derivation, type-level programming. Because their apparent value, one of the priorities in Scala 3 for us is to improve the conceptual framework behind them.
93+
94+
The state of context parameters before this release heavily employed the `given` keyword. For example:
95+
96+
```scala
97+
// OLD SYNTAX BELOW
98+
given String = "10"
99+
given (given str: String) : Int = str.toInt
100+
def f(x: Int)(given y: Int) = x * y
101+
```
102+
103+
The above is a suboptimal solution, however. The feedback we received from the community suggested that many people felt like the `given` keyword was overused, similarly to the `implict` keyword in Scala 2. This overuse is one of the things we'd like to avoid in Scala 3. It leads, for example, to situations like `given (given ...)` which are not nice to read.
104+
105+
For this release, we have changed the syntax for the context parameters. The keyword for the context argument group is now `using` instead of `given`. The above snippet now becomes:
106+
107+
```scala
108+
given String = "10"
109+
given (using str: String) as Int = str.toInt
110+
def f(x: Int)(using y: Int) = x * y
111+
```
112+
113+
On the call site, the syntax for explicitly specifying the context parameters is now:
114+
115+
```scala
116+
f(2)(using 20)
117+
```
118+
119+
As opposed to the previous:
120+
121+
```scala
122+
// OLD SYNTAX BELOW
123+
f(2)(given 20)
124+
```
125+
126+
For the time being, the change is experimental and the old syntax is also supported. For the discussion, see [PR #8162](https://github.com/lampepfl/dotty/pull/8162). You can browse the documentation concerning the new syntax [here](https://dotty.epfl.ch/docs/reference/contextual/motivation-new.html).
127+
128+
# Semantics of inline parameters changed
129+
Inline parameters is a metaprogramming feature of Dotty which allows to splice the body of the parameter on its call site. Previously, inline parameters to methods were required to be known on compile time. With this release, this constraint has been relaxed. The following:
130+
131+
```scala
132+
inline def sumTwice(a: Int, b: =>Int, inline c: Int) = a + a + b + b + c + c
133+
sumTwice(f(), g(), h())
134+
```
135+
136+
Translates to:
137+
138+
```scala
139+
val a = f()
140+
def b = g()
141+
a + a + b + b + h() + h()
142+
```
143+
144+
Notice how the value of the by-name parameter `b` is not inlined but is bound to `def b`. This is an important change that affects all the macros that accepted by-name parameters and analyzed the AST of the underlying code. With this release, such macros will stop working correctly because the AST of the code in question will be the identifier of the by-name parameter, `b` in this case, and not the AST of the code passed under that parameter's name. The workaround is to change all the by-name parameters in your macros to inline parameters.
145+
146+
So, if previously you had a macro `inline def operationOnCode(code: => Unit) = ${ mcrImpl('code) }` which did something on the AST of the passed `code`, with this release you need to change it to `inline def operationOnCode(inline code: Unit) = ${ mcrImpl('code) }`.
147+
148+
This change was introduced by [PR #8060](https://github.com/lampepfl/dotty/pull/8060/).
149+
150+
Another change in the semantics of the inline parameters involves the fact that the can no longer be passed as constants to macro implementations. Previously, the following was possible:
151+
152+
```scala
153+
// OLD SEMANTICS
154+
inline def power(x: Double, inline n: Int) = ${ powerCode('x, n) }
155+
private def powerCode(x: Expr[Double], n: Int)(given
156+
QuoteContext): Expr[Double] = ???
157+
```
158+
159+
It was possible to pass `n` directly to the spliced `powerCode` and it would have been treated as a constant in that macro implementation.
160+
161+
Now, the inline parameters must be quoted when passed to a macro:
162+
163+
```scala
164+
inline def power(x: Double, inline n: Int) = ${ powerCode('x, 'n) }
165+
private def powerCode(x: Expr[Double], n: Expr[Int])(given QuoteContext): Expr[Double] = ???
166+
```
167+
168+
You can obtain the constant value of `n` from within the macro implementation by calling `n.getValue` on it which returns an `Option`. This change was introduced by [PR #8061](https://github.com/lampepfl/dotty/pull/8061).
169+
170+
For more information about the inline capability of Dotty, see [documentation](https://dotty.epfl.ch/docs/reference/metaprogramming/inline.html).
171+
172+
# Primitive compiletime operations on singleton types
173+
Contributed by [Maxime Kjaer](https://github.com/MaximeKjaer), this release brings along type-level arithmetic:
174+
175+
```scala
176+
import scala.compiletime.ops.int._
177+
178+
val x: 2 + 3 = 5 // OK
179+
val y: 3 * 4 + 1 = 12 // error
180+
```
181+
182+
The compile-time error above will say:
183+
184+
```scala
185+
4 |val y: 3 * 4 + 1 = 12
186+
| ^^
187+
| Found: (12 : Int)
188+
| Required: (13 : Int)
189+
```
190+
191+
This feature is particularly useful for data science applications. In data science, it is very easy to make a linear algebra mistake, multiply matrices of wrong dimensions and get a runtime error – sometimes after a few hours of running the model. Hence compile-time verification of the models has a great potential for saving time. With such a type-level arithmetic, Scala becomes well-positioned to implement such type-safe data science frameworks.
192+
193+
For the discussion, see [PR #7628](https://github.com/lampepfl/dotty/pull/7628). The documentation is available [here](https://dotty.epfl.ch/docs/reference/metaprogramming/inline.html#the-scalacompiletimeops-package).
194+
195+
# Suggestions on missing context parameters
196+
If there's a compile-time error due to a missing context parameter and this error can be fixed with an import, the compiler will attempt to suggest such an import in the error message. Here is an example of how this error looks like:
197+
198+
```
199+
-- Error: tests/neg/missing-implicit1.scala:17:4 -----------------------------------------------------------------------
200+
17 | ff // error
201+
| ^
202+
|no implicit argument of type testObjectInstance.Zip[Option] was found for parameter xs of method ff in object testObjectInstance
203+
|
204+
|The following import might fix the problem:
205+
|
206+
| import testObjectInstance.instances.zipOption
207+
```
208+
209+
One area where these suggestions will make life easier is purely functional programming with type-classes, with libraries like [cats](https://typelevel.org/cats/). Having the fix for a missing type class in the error message itself is a big time-saver.
210+
211+
For the discussion, see [PR #7862](https://github.com/lampepfl/dotty/pull/7862).
212+
213+
# TASTy Inspector library
214+
TASTy Consumer was renamed to TASTy Inspector as of this release. It was also published in a library of its own. For more information, see the [documentation](https://dotty.epfl.ch/docs/reference/metaprogramming/tasty-inspect.html) on this library.
215+
216+
# Let us know what you think!
217+
218+
If you have questions or any sort of feedback, feel free to send us a message on our
219+
[Gitter channel](https://gitter.im/lampepfl/dotty). If you encounter a bug, please
220+
[open an issue on GitHub](https://github.com/lampepfl/dotty/issues/new).
221+
222+
## Contributing
223+
224+
Thank you to all the contributors who made this release possible!
225+
226+
According to `git shortlog -sn --no-merges 0.21.0-RC1..0.22.0-RC1` these are:
227+
228+
```
229+
192 Martin Odersky
230+
85 Nicolas Stucki
231+
57 Antoine Brunner
232+
42 Liu Fengyun
233+
29 Guillaume Martres
234+
23 Aggelos Biboudis
235+
17 Maxime Kjaer
236+
10 Anatolii
237+
7 Jamie Thompson
238+
4 Minghao Liu
239+
3 Travis Brown
240+
3 Andrew Valencik
241+
2 fhackett
242+
2 Dvir Faivel
243+
2 Nadezhda Balashova
244+
2 Ruslan Shevchenko
245+
2 Lan, Jian
246+
2 Anatolii Kmetiuk
247+
2 Yevgen Nerush
248+
1 Dale Wijnand
249+
1 odersky
250+
1 Dmitrii Naumenko
251+
1 Eric K Richardson
252+
1 Eric Loots
253+
1 Jaap van der Plas
254+
1 Keith Pinson
255+
1 Miles Sabin
256+
1 Alexander Shamukov
257+
1 Som Snytt
258+
1 Taisuke Oe
259+
1 Timothée Floure
260+
1 bishabosha
261+
1 gzoller
262+
```
263+
264+
If you want to get your hands dirty and contribute to Dotty, now is a good time to get involved!
265+
Head to our [Getting Started page for new contributors](https://dotty.epfl.ch/docs/contributing/getting-started.html),
266+
and have a look at some of the [good first issues](https://github.com/lampepfl/dotty/issues?q=is%3Aissue+is%3Aopen+label%3Aexp%3Anovice).
267+
They make perfect entry points into hacking on the compiler.
268+
269+
We are looking forward to having you join the team of contributors.
270+
271+
## Library authors: Join our community build
272+
273+
Dotty now has a set of widely-used community libraries that are built against every nightly Dotty
274+
snapshot. Currently, this includes ScalaPB, algebra, scalatest, scopt and squants.
275+
Join our [community build](https://github.com/lampepfl/dotty-community-build)
276+
to make sure that our regression suite includes your library.
277+
278+
[Scastie]: https://scastie.scala-lang.org/?target=dotty
279+
280+
[@odersky]: https://github.com/odersky
281+
[@DarkDimius]: https://github.com/DarkDimius
282+
[@smarter]: https://github.com/smarter
283+
[@felixmulder]: https://github.com/felixmulder
284+
[@nicolasstucki]: https://github.com/nicolasstucki
285+
[@liufengyun]: https://github.com/liufengyun
286+
[@OlivierBlanvillain]: https://github.com/OlivierBlanvillain
287+
[@biboudis]: https://github.com/biboudis
288+
[@allanrenucci]: https://github.com/allanrenucci
289+
[@Blaisorblade]: https://github.com/Blaisorblade
290+
[@Duhemm]: https://github.com/Duhemm
291+
[@AleksanderBG]: https://github.com/AleksanderBG
292+
[@milessabin]: https://github.com/milessabin
293+
[@anatoliykmetyuk]: https://github.com/anatoliykmetyuk

0 commit comments

Comments
 (0)