Skip to content

Commit 0513751

Browse files
authored
Add code tabs to Other changes page (#2725)
1 parent 8411c44 commit 0513751

File tree

1 file changed

+97
-56
lines changed

1 file changed

+97
-56
lines changed

_overviews/scala3-migration/incompat-other-changes.md

+97-56
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,18 @@ Some other features are simplified or restricted to make the language easier, sa
2525
An inherited member, from a parent trait or class, can shadow an identifier defined in an outer scope.
2626
That pattern is called inheritance shadowing.
2727

28-
```scala
28+
{% tabs shared-inheritance_1 %}
29+
{% tab 'Scala 2 and 3' %}
30+
~~~ scala
2931
object B {
3032
val x = 1
3133
class C extends A {
3234
println(x)
3335
}
3436
}
35-
```
37+
~~~
38+
{% endtab %}
39+
{% endtabs %}
3640

3741
For instance, in this preceding piece of code, the `x` term in C can refer to the `x` member defined in the outer class `B` or it can refer to a `x` member of the parent class `A`.
3842
You cannot know until you go to the definition of `A`.
@@ -42,8 +46,9 @@ This is known for being error prone.
4246
That's why, in Scala 3, the compiler requires disambiguation if the parent class `A` does actually have a member `x`.
4347

4448
It prevents the following piece of code from compiling.
45-
46-
```scala
49+
{% tabs scala-2-inheritance_2 %}
50+
{% tab 'Scala 2 Only' %}
51+
~~~ scala
4752
class A {
4853
val x = 2
4954
}
@@ -54,8 +59,11 @@ object B {
5459
println(x)
5560
}
5661
}
57-
```
62+
~~~
63+
{% endtab %}
64+
{% endtabs %}
5865

66+
But if you try to compile with Scala 3 you should see an error of the same kind as:
5967
{% highlight text %}
6068
-- [E049] Reference Error: src/main/scala/inheritance-shadowing.scala:9:14
6169
9 | println(x)
@@ -72,21 +80,24 @@ The [Scala 3 migration compilation](tooling-migration-mode.html) can automatical
7280
The Scala 3 compiler requires the constructor of private classes to be private.
7381

7482
For instance, in the example:
75-
76-
```scala
83+
{% tabs scala-2-constructor_1 %}
84+
{% tab 'Scala 2 Only' %}
85+
~~~ scala
7786
package foo
7887

7988
private class Bar private[foo] () {}
80-
```
89+
~~~
90+
{% endtab %}
91+
{% endtabs %}
8192

82-
The error message is:
83-
```
93+
If you try to compile in scala 3 you should get the following error message:
94+
{% highlight text %}
8495
-- Error: /home/piquerez/scalacenter/scala-3-migration-guide/incompat/access-modifier/src/main/scala-2.13/access-modifier.scala:4:19
8596
4 | private class Bar private[foo] ()
8697
| ^
8798
| non-private constructor Bar in class Bar refers to private class Bar
8899
| in its type signature (): foo.Foo.Bar
89-
```
100+
{% endhighlight %}
90101

91102
The [Scala 3 migration compilation](tooling-migration-mode.html) warns about this but no automatic rewrite is provided.
92103

@@ -97,8 +108,9 @@ The solution is to make the constructor private, since the class is private.
97108
In Scala 3, overriding a concrete def with an abstract def causes subclasses to consider the def abstract, whereas in Scala 2 it was considered as concrete.
98109

99110
In the following piece of code, the `bar` method in `C` is considered concrete by the Scala 2.13 compiler but abstract by the Scala 3 compiler, causing the following error.
100-
101-
```scala
111+
{% tabs scala-2-abstract_1 %}
112+
{% tab 'Scala 2 Only' %}
113+
~~~ scala
102114
trait A {
103115
def bar(x: Int): Int = x + 3
104116
}
@@ -107,8 +119,10 @@ trait B extends A {
107119
def bar(x: Int): Int
108120
}
109121

110-
class C extends B // Error: class C needs to be abstract, since def bar(x: Int): Int is not defined
111-
```
122+
class C extends B // In Scala 3, Error: class C needs to be abstract, since def bar(x: Int): Int is not defined
123+
~~~
124+
{% endtab %}
125+
{% endtabs %}
112126

113127
This behavior was decided in [Dotty issue #4770](https://github.com/lampepfl/dotty/issues/4770).
114128

@@ -120,17 +134,20 @@ The companion object of a case class does not extend any of the `Function{0-23}`
120134
In particular, it does not inherit their methods: `tupled`, `curried`, `andThen`, `compose`...
121135

122136
For instance, this is not permitted anymore:
123-
124-
```scala
137+
{% tabs scala-2-companion_1 %}
138+
{% tab 'Scala 2 Only' %}
139+
~~~ scala
125140
case class Foo(x: Int, b: Boolean)
126141

127142
Foo.curried(1)(true)
128143
Foo.tupled((2, false))
129-
```
144+
~~~
145+
{% endtab %}
146+
{% endtabs %}
130147

131148
A cross-compiling solution is to explicitly eta-expand the method `Foo.apply`.
132-
133149
{% highlight diff %}
150+
134151
-Foo.curried(1)(true)
135152
+(Foo.apply _).curried(1)(true)
136153

@@ -139,13 +156,16 @@ A cross-compiling solution is to explicitly eta-expand the method `Foo.apply`.
139156
{% endhighlight %}
140157

141158
Or, for performance reasons, you can introduce an intermediate function value.
142-
143-
```scala
159+
{% tabs scala-3-companion_2 %}
160+
{% tab 'Scala 2 and 3' %}
161+
~~~ scala
144162
val fooCtr: (Int, Boolean) => Foo = (x, b) => Foo(x, b)
145163

146164
fooCtr.curried(1)(true)
147165
fooCtr.tupled((2, false))
148-
```
166+
~~~
167+
{% endtab %}
168+
{% endtabs %}
149169
## Explicit Call to `unapply`
150170

151171
In Scala, case classes have an auto-generated extractor method, called `unapply` in their companion object.
@@ -156,36 +176,48 @@ The new signature is option-less (see the new [Pattern Matching]({{ site.scala3r
156176
Note that this problem does not affect user-defined extractors, whose signature stays the same across Scala versions.
157177

158178
Given the following case class definition:
159-
160-
```scala
179+
{% tabs shared-unapply_1 %}
180+
{% tab 'Scala 2 and 3' %}
181+
~~~ scala
161182
case class Location(lat: Double, long: Double)
162-
```
183+
~~~
184+
{% endtab %}
185+
{% endtabs %}
163186

164187
The Scala 2.13 compiler generates the following `unapply` method:
165-
166-
```scala
188+
{% tabs scala-2-unapply_2 %}
189+
{% tab 'Scala 2 Only' %}
190+
~~~ scala
167191
object Location {
168192
def unapply(location: Location): Option[(Double, Double)] = Some((location.lat, location.long))
169193
}
170-
```
194+
~~~
195+
{% endtab %}
196+
{% endtabs %}
171197

172198
Whereas the Scala 3 compiler generates:
173-
174-
```scala
199+
{% tabs scala-3-unapply_2 %}
200+
{% tab 'Scala 3 Only' %}
201+
~~~ scala
175202
object Location {
176203
def unapply(location: Location): Location = location
177204
}
178-
```
179-
180-
Consequently the following code does not compile anymore.
181-
182-
```scala
205+
~~~
206+
{% endtab %}
207+
{% endtabs %}
208+
209+
Consequently the following code does not compile anymore in Scala 3.
210+
{% tabs scala-2-unapply_3 %}
211+
{% tab 'Scala 2 Only' %}
212+
~~~ scala
183213
def tuple(location: Location): (Int, Int) = {
184-
Location.unapply(location).get // [E008] Not Found Error: value get is not a member of Location
214+
Location.unapply(location).get // [E008] In Scala 3, Not Found Error: value get is not a member of Location
185215
}
186-
```
216+
~~~
217+
{% endtab %}
218+
{% endtabs %}
187219

188-
A possible solution is to use pattern binding:
220+
A possible solution, in Scala 3, is to use pattern binding:
189221

190222
{% highlight diff %}
191223
def tuple(location: Location): (Int, Int) = {
@@ -199,21 +231,24 @@ def tuple(location: Location): (Int, Int) = {
199231

200232
The getter and setter methods generated by the `BeanProperty` annotation are now invisible in Scala 3 because their primary use case is the interoperability with Java frameworks.
201233

202-
For instance, in the below example:
203-
204-
```scala
234+
For instance, the below Scala 2 code would fail to compile in Scala 3:
235+
{% tabs scala-2-bean_1 %}
236+
{% tab 'Scala 2 Only' %}
237+
~~~ scala
205238
class Pojo() {
206239
@BeanProperty var fooBar: String = ""
207240
}
208241

209242
val pojo = new Pojo()
210243

211-
pojo.setFooBar("hello") // [E008] Not Found Error: value setFooBar is not a member of Pojo
244+
pojo.setFooBar("hello") // [E008] In Scala 3, Not Found Error: value setFooBar is not a member of Pojo
212245

213-
println(pojo.getFooBar()) // [E008] Not Found Error: value getFooBar is not a member of Pojo
214-
```
246+
println(pojo.getFooBar()) // [E008] In Scala 3, Not Found Error: value getFooBar is not a member of Pojo
247+
~~~
248+
{% endtab %}
249+
{% endtabs %}
215250

216-
The solution is to call the more idiomatic `pojo.fooBar` getter and setter.
251+
In Scala 3, the solution is to call the more idiomatic `pojo.fooBar` getter and setter.
217252

218253
{% highlight diff %}
219254
val pojo = new Pojo()
@@ -233,7 +268,7 @@ This decision is explained in [this comment](https://github.com/lampepfl/dotty/b
233268

234269
For instance, it is not allowed to pass a function of type `Int => (=> Int) => Int` to the `uncurried` method since it would assign `=> Int` to the type parameter `T2`.
235270

236-
```
271+
{% highlight text %}
237272
-- [E134] Type Mismatch Error: src/main/scala/by-name-param-type-infer.scala:3:41
238273
3 | val g: (Int, => Int) => Int = Function.uncurried(f)
239274
| ^^^^^^^^^^^^^^^^^^
@@ -244,7 +279,7 @@ For instance, it is not allowed to pass a function of type `Int => (=> Int) => I
244279
| [T1, T2, T3, R](f: T1 => T2 => T3 => R): (T1, T2, T3) => R
245280
| [T1, T2, R](f: T1 => T2 => R): (T1, T2) => R
246281
|match arguments ((Test.f : Int => (=> Int) => Int))
247-
```
282+
{% endhighlight %}
248283

249284
The solution depends on the situation. In the given example, you can either:
250285
- define your own `uncurried` method with the appropriate signature
@@ -254,15 +289,18 @@ The solution depends on the situation. In the given example, you can either:
254289

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

257-
For instance, the following example does not compile.
258-
259-
```scala
292+
For instance, the below Scala 2 code would fail to compile in Scala 3:
293+
{% tabs scala-2-wildcard_1 %}
294+
{% tab 'Scala 2 Only' %}
295+
~~~ scala
260296
trait Example {
261297
type Foo[A]
262298

263-
def f(foo: Foo[_]): Unit // [E043] Type Error: unreducible application of higher-kinded type Example.this.Foo to wildcard arguments
299+
def f(foo: Foo[_]): Unit // [E043] In Scala 3, Type Error: unreducible application of higher-kinded type Example.this.Foo to wildcard arguments
264300
}
265-
```
301+
~~~
302+
{% endtab %}
303+
{% endtabs %}
266304

267305
We can fix this by using a type parameter:
268306

@@ -272,10 +310,13 @@ We can fix this by using a type parameter:
272310
{% endhighlight %}
273311

274312
But this simple solution does not work when `Foo` is itself used as a type argument.
275-
276-
```scala
313+
{% tabs scala-2-wildcard_2 %}
314+
{% tab 'Scala 2 Only' %}
315+
~~~ scala
277316
def g(foos: Seq[Foo[_]]): Unit
278-
```
317+
~~~
318+
{% endtab %}
319+
{% endtabs %}
279320

280321
In such case, we can use a wrapper class around `Foo`:
281322

@@ -284,4 +325,4 @@ In such case, we can use a wrapper class around `Foo`:
284325

285326
-def g(foos: Seq[Foo[_]]): Unit
286327
+def g(foos: Seq[FooWrapper[_]]): Unit
287-
{% endhighlight %}
328+
{% endhighlight %}

0 commit comments

Comments
 (0)