Skip to content

Commit 9c4d401

Browse files
neko-kaiadpi2
authored andcommitted
Document migration to Scala 3 Underscore Type Lambdas syntax and cross-compiling with kind-projector
1 parent 2639df4 commit 9c4d401

File tree

3 files changed

+120
-3
lines changed

3 files changed

+120
-3
lines changed

docs/compiler-options/compiler-options-table.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,3 +272,4 @@ You can enable and configure them with some new native options.
272272
| 2.13.x | 3.0.x |
273273
|-|-|
274274
| `-Xplugin:kind-projector_<version>.jar` | `-Ykind-projector` |
275+
| `-P:kind-projector:underscore-placeholders` | `-Ykind-projector:underscores` |

docs/incompatibilities/other-changed-features.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,6 @@ The solution depends on the situation. In the given example, you can either:
250250

251251
Scala 3 cannot reduce the application of a higher-kinded abstract type member to the wildcard argument.
252252

253-
For instance, the following example does not compile.
254253
For instance, the following example does not compile.
255254

256255
```scala
@@ -271,14 +270,14 @@ We can fix this by using a type parameter:
271270
But this simple solution does not work when `Foo` is itself used as type argument.
272271

273272
```scala
274-
def g(foos: Seq[Foo[_]]): Unit`
273+
def g(foos: Seq[Foo[_]]): Unit
275274
```
276275

277276
In such case, we can use a wrapper class around `Foo`:
278277

279278
```diff
280279
+class FooWrapper[A](foo: Foo[A])
281280

282-
-def g(foos: Seq[Foo[_]]): Unit`
281+
-def g(foos: Seq[Foo[_]]): Unit
283282
+def g(foos: Seq[FooWrapper[_]]): Unit
284283
```

docs/tutorials/kind-projector.md

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
---
2+
id: kind-projector
3+
title: kind-projector Migration Tutorial
4+
---
5+
6+
In the future, Scala 3 will use the `_` underscore symbol for placeholders in type lambdas — just as the underscore is currently used for placeholders in ordinary lambdas.
7+
8+
The new type lambda syntax is not enabled by default, to enable it, use a compiler flag `-Ykind-projector:underscores`. Note that enabling underscore type lambdas will disable usage of `_` as a wildcard, you will only be able to write wildcards using the `?` symbol.
9+
10+
If you wish to cross-compile a project for Scala 2 & Scala 3 while using Underscore Type Lambdas for both, you may do so starting with [kind-projector](https://github.com/typelevel/kind-projector) version `0.13.0` and up and Scala 2 versions `2.13.5` and `2.12.14`.
11+
To enable it, add the compiler flags `-Xsource:3 -P:kind-projector:underscore-placeholders` to your build.
12+
As in Scala 3, this will disable usage of `_` as a wildcard, however, the flag `-Xsource:3` will allow you to replace it with the `?` symbol.
13+
14+
The following `sbt` configuration will set up the correct flags to cross-compile with new syntax:
15+
16+
```scala
17+
ThisBuild / scalacOptions ++= (if (scalaVersion.value.startsWith("3")) Seq("-Ykind-projector:underscores")
18+
else Seq("-Xsource:3", "-P:kind-projector:underscore-placeholders"))
19+
```
20+
21+
### Migrating to New Syntax
22+
23+
To use underscores for type-lambdas in existing kind-projector enabled code, replace `*` or `?` type lambda placeholders with `_`.
24+
25+
In turn, you will also have to rewrite all usages of `_` as the wildcard to use `?` symbol.
26+
27+
For example the following usage of the wildcard:
28+
29+
```scala
30+
def getWidget(widgets: Set[_ <: Widget], name: String): Option[Widget] = widgets.find(_.name == name)
31+
```
32+
33+
Must be rewritten to:
34+
35+
```scala
36+
def getWidget(widgets: Set[? <: Widget], name: String): Option[Widget] = widgets.find(_.name == name)
37+
```
38+
39+
And the following usages of kind-projector's `*` placeholder:
40+
41+
```scala
42+
Tuple2[*, Double] // equivalent to: type R[A] = Tuple2[A, Double]
43+
Either[Int, +*] // equivalent to: type R[+A] = Either[Int, A]
44+
Function2[-*, Long, +*] // equivalent to: type R[-A, +B] = Function2[A, Long, B]
45+
```
46+
47+
Must be rewritten to:
48+
49+
```scala
50+
Tuple2[_, Double] // equivalent to: type R[A] = Tuple2[A, Double]
51+
Either[Int, +_] // equivalent to: type R[+A] = Either[Int, A]
52+
Function2[-_, Long, +_] // equivalent to: type R[-A, +B] = Function2[A, Long, B]
53+
```
54+
55+
### Compiling Existing Code
56+
57+
Even without migrating to Underscore type lambdas, you will likely be able to compile most of it with Scala 3 without changes.
58+
59+
Use the flag `-Ykind-projector` to enable support for `*`-based type lambdas (without enabling underscore type lambdas), the following forms will now compile:
60+
61+
```scala
62+
Tuple2[*, Double] // equivalent to: type R[A] = Tuple2[A, Double]
63+
Either[Int, +*] // equivalent to: type R[+A] = Either[Int, A]
64+
Function2[-*, Long, +*] // equivalent to: type R[-A, +B] = Function2[A, Long, B]
65+
```
66+
67+
### Rewriting Incompatible Constructs
68+
69+
Scala 3's `-Ykind-projector` & `-Ykind-projector:underscores` implement only a subset of `kind-projector` syntax, in particular they do not implement:
70+
71+
* higher-kinded type lambda placeholders
72+
* higher-kinded named type lambda parameters
73+
* The `Lambda` keyword (`λ` is still supported)
74+
75+
You must rewrite ALL of the following forms:
76+
77+
```scala
78+
// classic
79+
EitherT[*[_], Int, *] // equivalent to: type R[F[_], B] = EitherT[F, Int, B]
80+
// underscores
81+
EitherT[_[_], Int, _] // equivalent to: type R[F[_], B] = EitherT[F, Int, B]
82+
// named λ
83+
λ[(F[_], A) => EitherT[F, Int, A]]
84+
// named Lambda
85+
Lambda[(F[_], A) => EitherT[F, Int, A]]
86+
```
87+
88+
Into the following long-form to cross-compile with Scala 3:
89+
90+
```scala
91+
type MyLambda[F[_], A] = EitherT[F, Int, A]
92+
MyLambda
93+
```
94+
95+
Alternatively you may use Scala 3's [Native Type Lambdas](https://dotty.epfl.ch/docs/reference/new-types/type-lambdas.html) if you do not need to cross-compile:
96+
97+
```scala
98+
[F[_], A] =>> EitherT[F, Int, A]
99+
```
100+
101+
For `Lambda` you must rewrite the following form:
102+
103+
```scala
104+
Lambda[(`+E`, `+A`) => Either[E, A]]
105+
```
106+
107+
To the following to cross-compile:
108+
109+
λ[(`+E`, `+A`) => Either[E, A]]
110+
111+
Or alternatively to Scala 3 Type Lambdas:
112+
113+
```scala
114+
[E, A] =>> Either[E, A]
115+
```
116+
117+
Note: Scala 3 Type Lambdas no longer need `-` or `+` variance markers on parameters, these are now inferred.

0 commit comments

Comments
 (0)