Skip to content

Commit bd1a311

Browse files
Add 23rd Release blog article
1 parent 74a67d0 commit bd1a311

File tree

1 file changed

+324
-0
lines changed

1 file changed

+324
-0
lines changed
Lines changed: 324 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,324 @@
1+
---
2+
layout: blog-page
3+
title: Announcing Dotty 0.23.0-RC1 - safe initialization checks, type-level bitwise operations and more
4+
author: Anatolii Kmetiuk
5+
authorImg: /images/anatolii.png
6+
date: 2020-03-18
7+
---
8+
9+
Hello! We are excited to announce 0.23.0-RC1 of Dotty. This version brings safe initialization checks, minor syntactic changes related to the context parameters, type-level bitwise operations and improvements of the metaprogramming capabilities.
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.
12+
13+
Alternatively, you can try this version of Scala online via [Scastie](https://scastie.scala-lang.org/). Once you're there, click "Build Settings" and set "Target" to "Dotty".
14+
15+
Enjoy the ride🚀!
16+
17+
<!--more-->
18+
# Cool new features
19+
## Safe initialization checks
20+
When a class is instantiated, the fields in the class body are initialized by field initializers, which could be any Scala code. Such a versatile language feature gives the programmer flexibility in defining how objects are initialized. However, such flexibility also brings complexity to ensure that we never accidentally use a field before it's initialized. Initialization errors can be difficult to spot in the presence of complex language features, such as inheritance, traits, inner classes, and aliasing. Such errors, sometimes simple sometimes subtle, require programmer efforts to debug and fix, which has been a [pain point for Scala programmers](https://contributors.scala-lang.org/t/improve-forward-reference-handling/3616) for a long time.
21+
22+
Most programming languages do not statically check initialization safety, such as C++, Java, Kotlin, etc.
23+
Or, they check initialization safety but overly restrict how objects are initialized, like Swift.
24+
Now, Scala 3 has the best of two worlds: flexibility of initialization patterns and static check for safety.
25+
26+
Consider the following program:
27+
28+
```scala
29+
abstract class AbstractFile {
30+
def name: String
31+
val extension: String = name.reverse.dropWhile(_ != '.').reverse
32+
}
33+
34+
class RemoteFile(url: String) extends AbstractFile {
35+
val localFile: String = url.hashCode + ".tmp"
36+
def name: String = localFile
37+
}
38+
```
39+
40+
Above, `extension` value is initialized prior to `localFile` because the fields of the parents of a class are initialized prior to the fields of the class. However, `extension` uses `localFile` during its initialization since it accesses this field from the `name` method. This scenario will lead to a `NullPointerException` on runtime when the access to uninitialized `localFile` happens.
41+
42+
43+
In this release, we have added an aid for the programmer to detect such mistakes automatically. If you compile the above program with the `-Ycheck-init` flag, you will get the following compile-time error:
44+
45+
```scala
46+
-- Error: /Users/kmetiuk/Projects/scala3/pg/release/snip_4.scala:8:7 -----------
47+
8 | val localFile: String = url.hashCode + ".tmp"
48+
| ^
49+
|Access non-initialized field localFile. Calling trace:
50+
| -> val extension: String = name.reverse.dropWhile(_ != '.').reverse [ snip_4.scala:4 ]
51+
| -> def name: String = localFile [ snip_4.scala:9 ]
52+
1 error found
53+
```
54+
55+
You can learn more about the feature from the [documentation](https://dotty.epfl.ch/0.23.0-RC1/docs/reference/other-new-features/safe-initialization.html). For the discussion, see PR [#7789](https://github.com/lampepfl/dotty/pull/7789).
56+
57+
## Bitwise Int compiletime operations
58+
In the previous release, Dotty has [received](https://dotty.epfl.ch/blog/2020/02/05/22nd-dotty-milestone-release.html#primitive-compiletime-operations-on-singleton-types) a support for type-level arithmetic operations on integers. In this release, we are extending this support by adding bitwise operations. For example:
59+
60+
```scala
61+
import scala.compiletime.ops.int._
62+
63+
@main def Test =
64+
val t1: 1 << 1 = 2
65+
val t2: 1 << 2 = 4
66+
val t3: 1 << 3 = 8
67+
val t4: 1 << 4 = 0 // error
68+
```
69+
70+
Above `t4` will fail to compile with the following error:
71+
72+
-- [E007] Type Mismatch Error: /Users/kmetiuk/Projects/scala3/pg/release/snip_3.scala:7:20
73+
7 | val t67: 1 << 4 = 0 // error
74+
| ^
75+
| Found: (0 : Int)
76+
| Required: (16 : Int)
77+
78+
You can find the list of all the supported operations in the `scala.compiletime.ops` [package](https://github.com/bishabosha/dotty/blob/e2b0de0bf70bbde5a9a92dc7fa91b36537b02a87/library/src/scala/compiletime/ops/package.scala)
79+
80+
# Syntactic Changes
81+
## Context functions syntax improved
82+
In this release, we have done some work to improve the syntax of context functions. Now, their syntax is closer to the syntax for context parameters of methods.
83+
84+
Previously, a context function was written as follows:
85+
86+
```scala
87+
// OLD SYNTAX
88+
val ctxFunOld = (x: String) ?=> x.toInt
89+
```
90+
91+
Now, it is written as follows:
92+
93+
```scala
94+
val ctxFunNew = (using x: String) => x.toInt
95+
```
96+
97+
We hope that this change will improve the readability of context functions for a person who already knows the syntax for context parameters of ordinary methods.
98+
99+
## Drop `given` parameter syntax
100+
As part of our experimentation with the syntax of the language, we are now dropping the old syntax for context parameters.
101+
102+
The old syntax for context parameters was as follows:
103+
104+
```scala
105+
// OLD SYNTAX, NO LONGER SUPPORTED
106+
def f(given x: Int) = x * x
107+
```
108+
109+
In the previous release, it was [replaced](https://dotty.epfl.ch/blog/2020/02/05/22nd-dotty-milestone-release.html#further-improvements-to-the-context-parameters-syntax) by the new `using` syntax:
110+
111+
```scala
112+
def f(using x: Int) = x * x
113+
```
114+
115+
However, both syntaxes were supported for that release for experimental purposes. Now, we are dropping the support of the old syntax in favor of the new one as we see it as a clear win over the old one.
116+
117+
# Metaprogramming
118+
## Inline version of `summon`
119+
Inside an inline method, we often want to summon a value without declaring it as a context parameter of the method:
120+
121+
```scala
122+
inline def lookup[X] =
123+
val x = summon[X] // error
124+
// -- Error: /Users/kmetiuk/Projects/scala3/pg/release/snip_5.scala:6:19 ----------
125+
// 6 | val x = summon[X]
126+
// | ^
127+
// |no implicit argument of type X was found for parameter x of method summon in object DottyPredef
128+
// 1 error found
129+
println(s"x = $x")
130+
```
131+
132+
The above program will give us a compile time error because it cannot find a context parameter of type `X`. This is because the `summon` function is not inline and hence the compiler needs to know that a context parameter of type `X` exists on call site of `summon` which happens to be in the body of `lookup`. Since `X` is unknown in that body, the compiler can't find the context parameter and shows an error.
133+
134+
We have now added an inline version of `summon`:
135+
136+
```scala
137+
import scala.compiletime.summonInline
138+
139+
inline def lookup[X] =
140+
val x = summonInline[X]
141+
println(s"x = $x")
142+
143+
@main def Test =
144+
given Int = 10
145+
lookup[Int]
146+
```
147+
148+
`summonInline` is an inline version of `summon`. It is defined as follows:
149+
150+
```scala
151+
inline def summonInline[T] <: T = summonFrom {
152+
case t: T => t
153+
}
154+
```
155+
156+
Since it is inline, the context parameter is resolved on expansion site, not the call site. The expansion site happens to be wherever `lookup` function is expanded, and there the type `X` is bound to a concrete type.
157+
158+
## `ValueOfExpr` renamed to `Unlifted`
159+
This feature allows you to obtain the value captured in an expression using pattern matching:
160+
161+
Macro.scala
162+
163+
```scala
164+
import scala.quoted._
165+
166+
inline def square(inline x: Int): Int = ${ squareImpl('x) }
167+
def squareImpl(x: Expr[Int])(using QuoteContext): Expr[Int] =
168+
x match
169+
case Unlifted(value: Int) => Expr(value * value)
170+
```
171+
172+
Test.scala
173+
174+
```scala
175+
@main def Test =
176+
println(square(10)) // println(100)
177+
```
178+
179+
## Extractors for quotes moved under `scala.quoted` package
180+
The metaprogramming capabilities are undergoing simplifications in this release. In particular, fewer imports are now needed.
181+
182+
Previously, to access the extractors for expressions you had to do the `scala.quoted.matching._` import. Now, the extractors from there have been moved to `scala.quoted`. For example, you can write the following program:
183+
184+
Macro.scala:
185+
186+
```scala
187+
import scala.quoted._
188+
189+
inline def square(inline x: Int): Int = ${ squareImpl('x) }
190+
def squareImpl(xExpr: Expr[Int])(using QuoteContext): Expr[Int] =
191+
xExpr match
192+
case Const(x) => Expr(x * x)
193+
```
194+
195+
Test.scala:
196+
197+
```scala
198+
@main def Test =
199+
println(square(2)) // println(4)
200+
```
201+
202+
Above, `Const` is an extractor that matches constants. Notice how we do not need to import anything else but `scala.quoted._` to use it.
203+
204+
## TASTy Reflect imports simplified
205+
Previously, to access TASTy Reflect features of Dotty, you had to include an import as follows:
206+
207+
```scala
208+
// OLD CODE
209+
import qctx.tasty.{ _, given }
210+
```
211+
212+
Above, `qctx` is a `QuoteContext` which is available in all the macro implementations. The `given` keyword imports all the context instances. In this particular case, it was needed to bring extension methods for ASTs in scope.
213+
214+
With this release, the `given` part is no longer needed and the extension methods are in scope after merely importing `import qctx.tasty._`.
215+
216+
Consider the following example:
217+
218+
Macro.scala
219+
220+
```scala
221+
import scala.quoted._
222+
223+
inline def showTree(inline x: Any): String = ${ showTreeImpl('x) }
224+
def showTreeImpl(x: Expr[Any])(using qctx: QuoteContext): Expr[String] =
225+
import qctx.tasty._
226+
x.unseal match
227+
case Inlined(_, _, app: Apply) =>
228+
val fun: Term = app.fun
229+
val args: List[Term] = app.args
230+
val res = s"Function: $fun\nApplied to: $args"
231+
Expr(res)
232+
```
233+
234+
Test.scala
235+
236+
```scala
237+
@main def Test =
238+
def f(x: Int) = x * x
239+
val x = 10
240+
println(showTree(f(x)))
241+
```
242+
243+
Notice how above, we are calling `app.fun` and `app.args`. `fun` and `args` are extension methods on `Apply` tree node. Previously they would not have been available unless we did `import qctx.tasty.given`. However as of this release, the above program compiles without errors.
244+
245+
# Let us know what you think!
246+
247+
If you have questions or any sort of feedback, feel free to send us a message on our
248+
[Gitter channel](https://gitter.im/lampepfl/dotty). If you encounter a bug, please
249+
[open an issue on GitHub](https://github.com/lampepfl/dotty/issues/new).
250+
251+
## Contributing
252+
253+
Thank you to all the contributors who made this release possible!
254+
255+
According to `git shortlog -sn --no-merges 0.22.0-RC1..0.23.0-RC1` these are:
256+
257+
```
258+
165 Martin Odersky
259+
124 Nicolas Stucki
260+
121 Liu Fengyun
261+
45 Robert Stoll
262+
15 Guillaume Martres
263+
15 Anatolii
264+
10 gzoller
265+
8 Som Snytt
266+
8 Stéphane Micheloud
267+
5 Ausmarton Zarino Fernandes
268+
5 Oron Port
269+
3 Adam Fraser
270+
3 Gabriele Petronella
271+
3 Uko
272+
3 Anatolii Kmetiuk
273+
2 ybasket
274+
2 Dale Wijnand
275+
2 Dani Rey
276+
2 Jamie Thompson
277+
2 Olivier Blanvillain
278+
2 Tomasz Godzik
279+
2 Travis Brown
280+
2 Vlastimil Dort
281+
1 tanaka takaya
282+
1 Miles Sabin
283+
1 Andrew Valencik
284+
1 bishabosha
285+
1 fhackett
286+
1 Lionel Parreaux
287+
1 kenji yoshida
288+
1 manojo
289+
1 odersky
290+
1 Raj Parekh
291+
1 Sébastien Doeraene
292+
1 xuwei-k
293+
```
294+
295+
If you want to get your hands dirty and contribute to Dotty, now is a good time to get involved!
296+
Head to our [Getting Started page for new contributors](https://dotty.epfl.ch/docs/contributing/getting-started.html),
297+
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).
298+
They make perfect entry points into hacking on the compiler.
299+
300+
We are looking forward to having you join the team of contributors.
301+
302+
## Library authors: Join our community build
303+
304+
Dotty now has a set of widely-used community libraries that are built against every nightly Dotty
305+
snapshot. Currently, this includes ScalaPB, algebra, scalatest, scopt and squants.
306+
Join our [community build](https://github.com/lampepfl/dotty-community-build)
307+
to make sure that our regression suite includes your library.
308+
309+
[Scastie]: https://scastie.scala-lang.org/?target=dotty
310+
311+
[@odersky]: https://github.com/odersky
312+
[@DarkDimius]: https://github.com/DarkDimius
313+
[@smarter]: https://github.com/smarter
314+
[@felixmulder]: https://github.com/felixmulder
315+
[@nicolasstucki]: https://github.com/nicolasstucki
316+
[@liufengyun]: https://github.com/liufengyun
317+
[@OlivierBlanvillain]: https://github.com/OlivierBlanvillain
318+
[@biboudis]: https://github.com/biboudis
319+
[@allanrenucci]: https://github.com/allanrenucci
320+
[@Blaisorblade]: https://github.com/Blaisorblade
321+
[@Duhemm]: https://github.com/Duhemm
322+
[@AleksanderBG]: https://github.com/AleksanderBG
323+
[@milessabin]: https://github.com/milessabin
324+
[@anatoliykmetyuk]: https://github.com/anatoliykmetyuk

0 commit comments

Comments
 (0)