You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: _overviews/scala3-migration/incompat-type-inference.md
+30-17
Original file line number
Diff line number
Diff line change
@@ -14,26 +14,15 @@ The new algorithm is better than the old one, but sometime it can fail where Sca
14
14
15
15
> It is always good practice to write the result types of all public values and methods explicitly.
16
16
> It prevents the public API of your library from changing with the Scala version, because of different inferred types.
17
-
>
17
+
>
18
18
> This can be done prior to the Scala 3 migration by using the [ExplicitResultTypes](https://scalacenter.github.io/scalafix/docs/rules/ExplicitResultTypes.html) rule in Scalafix.
19
19
20
20
## Return Type of an Override Method
21
21
22
22
In Scala 3 the return type of an override method is inferred by inheritance from the base method, whereas in Scala 2.13 it is inferred from the left hand side of the override method.
23
23
24
-
```scala
25
-
classParent {
26
-
deffoo:Foo=newFoo
27
-
}
28
-
29
-
classChildextendsParent {
30
-
overridedeffoo=newRichFoo(super.foo)
31
-
}
32
-
```
33
-
34
-
In this example, `Child#foo` returns a `RichFoo` in Scala 2.13 but a `Foo` in Scala 3.
35
-
It can lead to compiler errors as demonstrated below.
36
-
24
+
{% tabs define_parent_child %}
25
+
{% tab 'Scala 2 and 3' %}
37
26
```scala
38
27
classFoo
39
28
@@ -48,13 +37,24 @@ class Parent {
48
37
classChildextendsParent {
49
38
overridedeffoo=newRichFoo(super.foo)
50
39
}
40
+
```
41
+
{% endtab %}
42
+
{% endtabs %}
43
+
44
+
In this example, `Child#foo` returns a `RichFoo` in Scala 2.13 but a `Foo` in Scala 3.
45
+
It can lead to compiler errors as demonstrated below.
51
46
47
+
{% tabs extend_parent_child %}
48
+
{% tab 'Scala 3 Only' %}
49
+
```scala
52
50
(newChild).foo.show // Scala 3 error: value show is not a member of Foo
53
51
```
52
+
{% endtab %}
53
+
{% endtabs %}
54
54
55
55
In some rare cases involving implicit conversions and runtime casting it could even cause a runtime failure.
56
56
57
-
The solution is to make the return type of the override method explicit:
57
+
The solution is to make the return type of the override method explicit so that it matches what is inferred in 2.13:
58
58
59
59
{% highlight diff %}
60
60
class Child extends Parent {
@@ -68,19 +68,32 @@ class Child extends Parent {
68
68
Scala 2 reflective calls are dropped and replaced by the broader [Programmatic Structural Types]({{ site.scala3ref }}/changed-features/structural-types.html).
69
69
70
70
Scala 3 can imitate Scala 2 reflective calls by making `scala.reflect.Selectable.reflectiveSelectable` available wherever `scala.language.reflectiveCalls` is imported.
71
-
However the Scala 3 compiler does not infer structural types by default, and thus fails at compiling:
72
71
72
+
{% tabs define_structural %}
73
+
{% tab 'Scala 2 and 3' %}
73
74
```scala
74
75
importscala.language.reflectiveCalls
75
76
76
77
valfoo=new {
77
78
defbar:Unit=???
78
79
}
80
+
```
81
+
{% endtab %}
82
+
{% endtabs %}
79
83
84
+
However the Scala 3 compiler does not infer structural types by default.
85
+
It infers the type `Object` for `foo` instead of `{ def bar: Unit }`.
86
+
Therefore, the following structural selection fails to compile:
87
+
88
+
{% tabs use_structural %}
89
+
{% tab 'Scala 3 Only' %}
90
+
```scala
80
91
foo.bar // Error: value bar is not a member of Object
81
92
```
93
+
{% endtab %}
94
+
{% endtabs %}
82
95
83
-
The straightforward solution is to write down the structural type.
96
+
The straightforward solution is to explicitly write down the structural type.
Copy file name to clipboardExpand all lines: _overviews/scala3-migration/plugin-kind-projector.md
+50-4
Original file line number
Diff line number
Diff line change
@@ -9,11 +9,11 @@ next-page: external-resources
9
9
10
10
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) term-level lambdas.
11
11
12
-
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.
12
+
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.
13
13
14
14
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.6` and `2.12.14`.
15
15
To enable it, add the compiler flags `-Xsource:3 -P:kind-projector:underscore-placeholders` to your build.
16
-
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.
16
+
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.
17
17
18
18
The following `sbt` configuration will set up the correct flags to cross-compile with new syntax:
19
19
@@ -34,43 +34,65 @@ In turn, you will also have to rewrite all usages of `_` as the wildcard to use
And the following usages of kind-projector's `*` placeholder:
48
58
59
+
{% tabs kind_projector_scala2 %}
60
+
{% tab 'Scala 2 Only' %}
49
61
```scala
50
62
Tuple2[*, Double] // equivalent to: type R[A] = Tuple2[A, Double]
51
63
Either[Int, +*] // equivalent to: type R[+A] = Either[Int, A]
52
64
Function2[-*, Long, +*] // equivalent to: type R[-A, +B] = Function2[A, Long, B]
53
65
```
66
+
{% endtab %}
67
+
{% endtabs %}
54
68
55
69
Must be rewritten to:
56
70
71
+
{% tabs kind_projector_scala3 %}
72
+
{% tab 'Scala 3 Only' %}
57
73
```scala
58
74
Tuple2[_, Double] // equivalent to: type R[A] = Tuple2[A, Double]
59
75
Either[Int, +_] // equivalent to: type R[+A] = Either[Int, A]
60
76
Function2[-_, Long, +_] // equivalent to: type R[-A, +B] = Function2[A, Long, B]
61
77
```
78
+
{% endtab %}
79
+
{% endtabs %}
62
80
63
81
## Compiling Existing Code
64
82
65
83
Even without migrating to underscore type lambdas, you will likely be able to compile most of it with Scala 3 without changes.
66
84
67
85
Use the flag `-Ykind-projector` to enable support for `*`-based type lambdas (without enabling underscore type lambdas), the following forms will now compile:
68
86
87
+
{% tabs kind_projector_cross %}
88
+
{% tab 'Scala 2 and 3' %}
69
89
```scala
70
90
Tuple2[*, Double] // equivalent to: type R[A] = Tuple2[A, Double]
71
91
Either[Int, +*] // equivalent to: type R[+A] = Either[Int, A]
72
92
Function2[-*, Long, +*] // equivalent to: type R[-A, +B] = Function2[A, Long, B]
73
93
```
94
+
{% endtab %}
95
+
{% endtabs %}
74
96
75
97
## Rewriting Incompatible Constructs
76
98
@@ -82,6 +104,8 @@ Scala 3's `-Ykind-projector` & `-Ykind-projector:underscores` implement only a s
82
104
83
105
You must rewrite ALL of the following forms:
84
106
107
+
{% tabs kind_projector_illegal_scala2 %}
108
+
{% tab 'Scala 2 Only' %}
85
109
```scala
86
110
// classic
87
111
EitherT[*[_], Int, *] // equivalent to: type R[F[_], B] = EitherT[F, Int, B]
@@ -92,36 +116,58 @@ EitherT[_[_], Int, _] // equivalent to: type R[F[_], B] = EitherT[F, Int, B]
92
116
// named Lambda
93
117
Lambda[(F[_], A) =>EitherT[F, Int, A]]
94
118
```
119
+
{% endtab %}
120
+
{% endtabs %}
95
121
96
122
Into the following long-form to cross-compile with Scala 3:
97
123
124
+
{% tabs kind_projector_illegal_cross %}
125
+
{% tab 'Scala 2 and 3' %}
98
126
```scala
99
127
typeMyLambda[F[_], A] =EitherT[F, Int, A]
100
128
MyLambda
101
129
```
130
+
{% endtab %}
131
+
{% endtabs %}
102
132
103
133
Alternatively you may use Scala 3's [Native Type Lambdas]({{ site.scala3ref }}/new-types/type-lambdas.html) if you do not need to cross-compile:
104
134
135
+
{% tabs kind_projector_illegal_scala3 %}
136
+
{% tab 'Scala 3 Only' %}
105
137
```scala
106
138
[F[_], A] =>>EitherT[F, Int, A]
107
139
```
140
+
{% endtab %}
141
+
{% endtabs %}
108
142
109
143
For `Lambda` you must rewrite the following form:
110
144
145
+
{% tabs kind_projector_illegal_lambda_scala2 %}
146
+
{% tab 'Scala 2 Only' %}
111
147
```scala
112
148
Lambda[(`+E`, `+A`) =>Either[E, A]]
113
149
```
150
+
{% endtab %}
151
+
{% endtabs %}
114
152
115
153
To the following to cross-compile:
116
154
155
+
{% tabs kind_projector_illegal_lambda_cross %}
156
+
{% tab 'Scala 2 and 3' %}
117
157
```scala
118
158
λ[(`+E`, `+A`) =>Either[E, A]]
119
159
```
160
+
{% endtab %}
161
+
{% endtabs %}
120
162
121
163
Or alternatively to Scala 3 type lambdas:
122
164
165
+
{% tabs kind_projector_illegal_lambda_scala3 %}
166
+
{% tab 'Scala 3 Only' %}
123
167
```scala
124
168
[E, A] =>>Either[E, A]
125
169
```
170
+
{% endtab %}
171
+
{% endtabs %}
126
172
127
173
Note: Scala 3 type lambdas no longer need `-` or `+` variance markers on parameters, these are now inferred.
This tutorial shows how to mix Scala 2.13 and Scala 3 macros in a single artifact. This means that consumers can use '-Ytasty-reader' from Scala 2.13 code that uses your macros.
10
+
This tutorial shows how to mix Scala 2.13 and Scala 3 macros in a single artifact. This means that consumers can use `-Ytasty-reader` from Scala 2.13 code that uses your macros.
0 commit comments