@@ -9,11 +9,9 @@ Scala 3 is coming, with a release candidate slated for the end of 2020.
9
9
With that knowledge comes the inevitable question:
10
10
should I migrate, and what is the potential cost?
11
11
12
- With this blog we would like to outline some scenarios for maintainers of projects who
13
- want to move to Scala 3, and how these
14
- scenarios are made simpler by the ability to read Scala 3 compiled dependencies
15
- from Scala 2.13. There is also a [ troubleshooting] ( #troubleshooting ) section
16
- in case you encounter issues following the steps described in the scenarios.
12
+ For maintainers of projects, the migration process may become easier
13
+ with the release of Scala 2.13.4, which comes with a new feature:
14
+ reading and compiling against Scala 3 dependencies.
17
15
18
16
> As a quick aside, If you would like to know how it is possible to mix
19
17
> dependencies between the two compilers, watch the talk
@@ -24,17 +22,42 @@ in case you encounter issues following the steps described in the scenarios.
24
22
> which terms, types and implicits are defined in a given dependency,
25
23
> and what code needs to be generated to use them correctly.
26
24
25
+ ## Overview
26
+
27
+ With a guided tutorial, we will show you how to approach the following scenarios:
28
+ 1 . You have an application consisting of many subprojects that may depend on
29
+ each other, built with Scala 2.13, and would like to transition each one
30
+ independently to Scala 3.0
31
+ 2 . You have an application, built with Scala 2.13, and want to use some
32
+ new features of a library that has migrated to Scala 3.0
33
+
34
+ We will show you by example how Scala 2.13.4 makes these scenarios more simple:
35
+ We will take a small multi-module project of two sub-projects, a ` shared ` module,
36
+ containing simple data structures, and an ` app ` module that depends on ` shared ` .
37
+ We will in turn migrate each sub-project to Scala 3, and show that it does not
38
+ matter in which order you migrate the projects, as ` app ` will continue
39
+ to build and run.
40
+
41
+ A reader applying the steps in the tutorial to their own project should note that not
42
+ all features of Scala 3 are forward compatibile with Scala 2, such as ` inline ` methods.
43
+ Consequently, we recommend that the user limits their usage of Scala 3 exclusive
44
+ features when migrating incrementally. More information is provided in the
45
+ [ forward compatibility] ( #forward-compatibility ) section.
46
+
47
+ In addition, we provide a [ troubleshooting] ( #troubleshooting ) section for the reader,
48
+ which aims to suggest steps to take when applying this guide to their own projects
49
+ and a problem occurs.
50
+
27
51
## Scenarios
28
52
29
- 1 . You have an application consisting of many subprojects that may depend on
30
- each other, built with Scala 2.13, and would like to transition each one
31
- independently to Scala 3.0
32
- 2 . You have an application, built with Scala 2.13, and want to use some
33
- new features of a library that has migrated to Scala 3.0
53
+ The [ overview] ( #overview ) section describes two scenarios that we will guide you through
54
+ in this blog:
55
+ - Migrating multi-module projects incrementally from Scala 2 to Scala 3
56
+ - Taking advantage of new features in a library that is published for Scala 3.
34
57
35
- Let's take a look at each scenario in turn:
58
+ Let's look at each scenario in turn:
36
59
37
- ## Migrating a multi module project
60
+ ### 1. Migrate a Multi-Module Project in Any Order
38
61
39
62
If you want to migrate a multi module project to Scala 3,
40
63
it does not matter in which order you migrate the modules, they will be
@@ -47,19 +70,15 @@ which has some common domain model data structures, and `app`,
47
70
which uses those data structures.
48
71
49
72
For this project, we will pick
50
- [ sbt 1.4.0 ] ( https://github.com/sbt/sbt/releases/tag/v1.4.0 ) ,
73
+ [ sbt 1.4.2 ] ( https://github.com/sbt/sbt/releases/tag/v1.4.2 ) ,
51
74
this allows you to mix projects of different Scala versions with very
52
75
little extra effort (thanks to Eugene Yokota).
53
76
54
- This tutorial also assumes the release of Scala ` 2.13.4 ` , but if you would
55
- like to follow along today, you can [ modify the build file] ( #early-access )
56
- to use an early access snapshot release.
57
-
58
77
To begin, our project looks like the following:
59
78
60
79
``` scala
61
80
// project/build.properties
62
- sbt.version= 1.4.0
81
+ sbt.version= 1.4.2
63
82
```
64
83
65
84
``` scala
@@ -106,16 +125,15 @@ Tiger
106
125
```
107
126
108
127
At this point we can try something exciting, compile either subproject with
109
- Scala 3 and see if it works. At the time of writing, the Scala version
110
- ` 0.27.0-RC1 ` is the latest preview release of Scala 3.
128
+ Scala 3 and see if it works.
111
129
112
130
First, add the dotty plugin (this helps with managing and inspecting the
113
131
` scalaVersion ` setting with Scala 3)
114
132
115
133
``` scala
116
134
// project/plugins.sbt
117
135
118
- addSbtPlugin(" ch.epfl.lamp" % " sbt-dotty" % " 0.4.2 " )
136
+ addSbtPlugin(" ch.epfl.lamp" % " sbt-dotty" % " 0.4.5 " )
119
137
```
120
138
121
139
Then we can change the ` scalaVersion ` of ` app ` :
@@ -129,7 +147,7 @@ Then we can change the `scalaVersion` of `app`:
129
147
130
148
lazy val app = project
131
149
.dependsOn(shared)
132
- + .settings(scalaVersion := "0.27.0-RC1 ")
150
+ + .settings(scalaVersion := "3.0.0-M1 ")
133
151
{% endhighlight %}
134
152
135
153
To recap, ` app ` is now compiled by Scala 3 and depends on ` shared ` ,
@@ -138,19 +156,21 @@ which is compiled by Scala 2.13.
138
156
If we do ` sbt app/run ` we should see the ` app ` project recompile
139
157
and it will run as before.
140
158
141
- Now lets try the other way around:
159
+ Now lets try the other way around, in this case we also have to enable
160
+ reading Scala 3 dependencies in Scala 2 with the flag ` -Ytasty-reader ` :
142
161
143
162
{% highlight diff %}
144
163
// build.sbt
145
164
146
165
ThisBuild / scalaVersion := "2.13.4"
147
166
148
167
lazy val shared = project
149
- + .settings(scalaVersion := "0.27.0-RC1 ")
168
+ + .settings(scalaVersion := "3.0.0-M1 ")
150
169
151
170
lazy val app = project
152
171
.dependsOn(shared)
153
- - .settings(scalaVersion := "0.27.0-RC1")
172
+ - .settings(scalaVersion := "3.0.0-M1")
173
+ + .settings(scalacOptions += "-Ytasty-reader")
154
174
{% endhighlight %}
155
175
156
176
Here we have the opposite, ` app ` is compiled by Scala 2.13 and depends
@@ -159,8 +179,8 @@ the command `sbt 'show app/dependencyTree'`, which outputs the following:
159
179
160
180
```
161
181
app:app_2.13:0.1.0-SNAPSHOT [S]
162
- +-shared:shared_0.27 :0.1.0-SNAPSHOT
163
- +-ch.epfl.lamp:dotty-library_0.27:0.27.0-RC1 [S]
182
+ +-shared:shared_3.0.0-M1 :0.1.0-SNAPSHOT
183
+ +-org.scala-lang:scala3-library_3.0.0-M1:3.0.0-M1 [S]
164
184
```
165
185
166
186
If we then try ` sbt app/run ` both ` shared ` and ` app ` subprojects will recompile
@@ -172,7 +192,11 @@ To summarise this part, we have shown that it is possible to migrate subprojects
172
192
to Scala 3 from Scala 2.13 in any order, gradually, and continue to build and
173
193
run them if they mix versions.
174
194
175
- ## Using a Scala 3 Library Dependency
195
+ ### 2. Using a Scala 3 Library Dependency
196
+
197
+ > TODO: there is currently no library published for Scala ` 3.0.0-M1 `
198
+ > we can either rewrite this section to just explain it in principle,
199
+ > with a fake library or wait for some library to be available.
176
200
177
201
In the section above, we have seen how it is possible for a subproject compiled
178
202
with Scala 2.13 to depend on a subproject compiled with Scala 3. The same
@@ -187,12 +211,12 @@ on the fansi library to `app` and try to change our output to be colored blue:
187
211
ThisBuild / scalaVersion := "2.13.4"
188
212
189
213
lazy val shared = project
190
- .settings(scalaVersion := "0.27.0-RC1 ")
214
+ .settings(scalaVersion := "3.0.0-M1 ")
191
215
192
216
lazy val app = project
193
217
.dependsOn(shared)
194
218
+ .settings(
195
- + libraryDependencies += "com.lihaoyi" % "fansi_0.27 " % "0.2.9"
219
+ + libraryDependencies += "com.lihaoyi" % "fansi_3.0.0-M1 " % "0.2.9" // TODO fansi has not been published for ` 3.0.0-M1 `
196
220
+ )
197
221
{% endhighlight %}
198
222
@@ -201,11 +225,11 @@ we take a standard module id and change it as so:
201
225
202
226
{% highlight diff %}
203
227
-"com.lihaoyi" %% "fansi" % "0.2.9"
204
- +"com.lihaoyi" % "fansi_0.27 " % "0.2.9"
228
+ +"com.lihaoyi" % "fansi_3.0.0-M1 " % "0.2.9"
205
229
{% endhighlight %}
206
230
207
231
By replacing ` %% ` with ` % ` , we can then manually specify the binary version,
208
- leading us to add ` _0.27 ` to the name of the module.
232
+ leading us to add ` _3.0.0-M1 ` to the name of the module.
209
233
210
234
We now update ` Main.scala ` to use the fansi library:
211
235
@@ -227,18 +251,72 @@ If we then run again `sbt 'show app/dependencyTree'` we see the following:
227
251
228
252
```
229
253
app:app_2.13:0.1.0-SNAPSHOT [S]
230
- +-com.lihaoyi:fansi_0.27 :0.2.9
231
- | +-com.lihaoyi:sourcecode_0.27 :0.2.1
254
+ +-com.lihaoyi:fansi_3.0.0-M1 :0.2.9
255
+ | +-com.lihaoyi:sourcecode_3.0.0-M1 :0.2.1
232
256
|
233
- +-shared:shared_0.27 :0.1.0-SNAPSHOT
234
- +-ch.epfl.lamp:dotty-library_0.27:0.27.0-RC1 [S]
257
+ +-shared:shared_3.0.0-M1 :0.1.0-SNAPSHOT
258
+ +-org.scala-lang:scala3-library_3.0.0-M1:3.0.0-M1 [S]
235
259
```
236
260
237
261
To summarise, in this section we have shown how it is possible to use a
238
262
third party library dependency, compiled with Scala 3, from Scala 2.13.
239
263
If there are issues with changing the binary version of a particular
240
264
dependency you have, check out the [ troubleshooting] ( #troubleshooting ) section.
241
265
266
+ ## Forward Compatibility
267
+ When migrating a subproject to Scala 3, where downstream consuming subprojects are likely to be on Scala 2.13, we would recommend restricting the usage of new features in Scala 3. This will maximise compatibility as you migrate each subproject. However, it is possible to start using some features of Scala 3 without issue, this is due to a limited forward compatibility in Scala 2.13 with some new Scala 3 features.
268
+
269
+ Forward compatibility means that many definitions created by using new Scala 3 features
270
+ can be used from Scala 2.13, however they will be remapped to features
271
+ that exist in Scala 2.13. For example,
272
+ [ extension methods] ( http://dotty.epfl.ch/docs/reference/contextual/extension-methods.html )
273
+ can only be used as ordinary methods. So for cross-compatible code we recommend
274
+ to continue using implicit classes to encode extension methods.
275
+
276
+ On the other hand, some features of Scala 3 are not mappable to features in Scala 2.13,
277
+ and will cause a compile-time error when using them. A longer list can be seen in the
278
+ migration guide, describing [ how Scala 2 reacts to different Scala 3 features] ( https://scalacenter.github.io/scala-3-migration-guide/docs/compatibility.html#the-scala-2-tasty-reader ) .
279
+
280
+ For unsupported features, a best effort is made
281
+ to report errors at the use-site that is problematic. For example,
282
+ [ match types] ( http://dotty.epfl.ch/docs/reference/new-types/match-types.html )
283
+ are not supported. If we define in the ` shared ` project the type ` Elem ` :
284
+
285
+ ``` scala
286
+ // shared/src/main/scala/example/MatchTypes.scala
287
+ package example
288
+
289
+ object MatchTypes {
290
+ type Elem [X ] = X match {
291
+ case List [t] => t
292
+ case Array [t] => t
293
+ }
294
+ }
295
+ ```
296
+
297
+ and then try to use it in the ` app ` project:
298
+
299
+ ``` scala
300
+ // app/src/main/scala/example/TestMatchTypes.scala
301
+ package example
302
+
303
+ object TestMatchTypes {
304
+ def test : MatchTypes .Elem [List [String ]] = " hello"
305
+ }
306
+ ```
307
+
308
+ we get the following error when calling ` sbt app/run ` :
309
+
310
+ ```
311
+ [error] TestMatchTypes.scala:5:25: Unsupported Scala 3 match type in bounds of type Elem; found in object example.MatchTypes.
312
+ [error] def test: MatchTypes.Elem[List[String]] = "hello"
313
+ [error] ^
314
+ [error] one error found
315
+ ```
316
+
317
+ The error is standard for all unsupported Scala 3 features, naming the feature,
318
+ the location of the definition and the location where it is used.
319
+
242
320
## Troubleshooting
243
321
There are some situations where the steps described in the sections above do
244
322
not work out of the box for your own project, and some other considerations
@@ -295,59 +373,6 @@ compilation, or disrupts runtime behaviour, please consider the above
295
373
troubleshooting topics, but instead assume that ` A ` is the third party
296
374
library, and ` B ` is your Scala 2.13 project that depends on it.
297
375
298
- ## Forward Compatibility
299
- When migrating a subproject to Scala 3, where downstream consuming subprojects are likely to be on Scala 2.13, we would recommend restricting the usage of new features in Scala 3. This will maximise compatibility as you migrate each subproject. However, it is possible to start using some features of Scala 3 without issue, this is due to a limited forward compatibility in Scala 2.13 with some new Scala 3 features.
300
-
301
- Forward compatibility means that many definitions created by using new Scala 3 features
302
- can be used from Scala 2.13, however they will be remapped to features
303
- that exist in Scala 2.13. For example,
304
- [ extension methods] ( http://dotty.epfl.ch/docs/reference/contextual/extension-methods.html )
305
- can only be used as ordinary methods, using their expanded name.
306
-
307
- On the other hand, some features of Scala 3 are not mappable to features in Scala 2.13,
308
- and will cause a compile-time error when using them. A longer list can be seen in the
309
- migration guide, describing [ how Scala 2 reacts to different Scala 3 features] ( https://scalacenter.github.io/scala-3-migration-guide/docs/compatibility.html#the-scala-2-tasty-reader ) .
310
-
311
- For unsupported features, a best effort is made
312
- to report errors at the use-site that is problematic. For example,
313
- [ match types] ( http://dotty.epfl.ch/docs/reference/new-types/match-types.html )
314
- are not supported. If we define in the ` shared ` project the type ` Elem ` :
315
-
316
- ``` scala
317
- // shared/src/main/scala/example/MatchTypes.scala
318
- package example
319
-
320
- object MatchTypes {
321
- type Elem [X ] = X match {
322
- case List [t] => t
323
- case Array [t] => t
324
- }
325
- }
326
- ```
327
-
328
- and then try to use it in the ` app ` project:
329
-
330
- ``` scala
331
- // app/src/main/scala/example/TestMatchTypes.scala
332
- package example
333
-
334
- object TestMatchTypes {
335
- def test : MatchTypes .Elem [List [String ]] = " hello"
336
- }
337
- ```
338
-
339
- we get the following error when calling ` sbt app/run ` :
340
-
341
- ```
342
- [error] TestMatchTypes.scala:5:25: Unsupported Scala 3 match type in bounds of type Elem; found in object example.MatchTypes.
343
- [error] def test: MatchTypes.Elem[List[String]] = "hello"
344
- [error] ^
345
- [error] one error found
346
- ```
347
-
348
- The error is standard for all unsupported Scala 3 features, naming the feature,
349
- the location of the definition and the location where it is used.
350
-
351
376
## Contributing
352
377
353
378
If you have found an issue with Scala 3 dependencies in Scala 2.13 and want to try
@@ -362,24 +387,6 @@ project to Scala 3 while continuing to use all the parts together during the
362
387
transition. We encourage you to try out this process and let us know of any
363
388
issues with using Scala 3 dependencies from Scala 2.13.
364
389
365
- ## Early Access
366
-
367
- If you would like to try out Scala 3 dependencies early, you can use a
368
- snapshot version of Scala 2.13.4 by adding the Scala integration resolver
369
- to your build:
370
-
371
- {% highlight diff %}
372
- // build.sbt
373
-
374
- -ThisBuild / scalaVersion := "2.13.4"
375
- +ThisBuild / scalaVersion := "2.13.4-bin-8891679"
376
-
377
- +Global / resolvers += "scala-integration".at(
378
- + "https://scala-ci.typesafe.com/artifactory/scala-integration/ ")
379
-
380
- ...
381
- {% endhighlight %}
382
-
383
390
## Important Links
384
391
385
392
- [ Scala 3 Migration Guide] ( https://scalacenter.github.io/scala-3-migration-guide/ )
0 commit comments