Skip to content

Add code tabs to Other changes page #2725

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Mar 13, 2023
Merged
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
153 changes: 97 additions & 56 deletions _overviews/scala3-migration/incompat-other-changes.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,18 @@ Some other features are simplified or restricted to make the language easier, sa
An inherited member, from a parent trait or class, can shadow an identifier defined in an outer scope.
That pattern is called inheritance shadowing.

```scala
{% tabs shared-inheritance_1 %}
{% tab 'Scala 2 and 3' %}
~~~ scala
object B {
val x = 1
class C extends A {
println(x)
}
}
```
~~~
{% endtab %}
{% endtabs %}

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`.
You cannot know until you go to the definition of `A`.
Expand All @@ -42,8 +46,9 @@ This is known for being error prone.
That's why, in Scala 3, the compiler requires disambiguation if the parent class `A` does actually have a member `x`.

It prevents the following piece of code from compiling.

```scala
{% tabs scala-2-inheritance_2 %}
{% tab 'Scala 2 Only' %}
~~~ scala
class A {
val x = 2
}
Expand All @@ -54,8 +59,11 @@ object B {
println(x)
}
}
```
~~~
{% endtab %}
{% endtabs %}

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

For instance, in the example:

```scala
{% tabs scala-2-constructor_1 %}
{% tab 'Scala 2 Only' %}
~~~ scala
package foo

private class Bar private[foo] () {}
```
~~~
{% endtab %}
{% endtabs %}

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

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

Expand All @@ -97,8 +108,9 @@ The solution is to make the constructor private, since the class is private.
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.

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.

```scala
{% tabs scala-2-abstract_1 %}
{% tab 'Scala 2 Only' %}
~~~ scala
trait A {
def bar(x: Int): Int = x + 3
}
Expand All @@ -107,8 +119,10 @@ trait B extends A {
def bar(x: Int): Int
}

class C extends B // Error: class C needs to be abstract, since def bar(x: Int): Int is not defined
```
class C extends B // In Scala 3, Error: class C needs to be abstract, since def bar(x: Int): Int is not defined
~~~
{% endtab %}
{% endtabs %}

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

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

For instance, this is not permitted anymore:

```scala
{% tabs scala-2-companion_1 %}
{% tab 'Scala 2 Only' %}
~~~ scala
case class Foo(x: Int, b: Boolean)

Foo.curried(1)(true)
Foo.tupled((2, false))
```
~~~
{% endtab %}
{% endtabs %}

A cross-compiling solution is to explicitly eta-expand the method `Foo.apply`.

{% highlight diff %}

-Foo.curried(1)(true)
+(Foo.apply _).curried(1)(true)

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

Or, for performance reasons, you can introduce an intermediate function value.

```scala
{% tabs scala-3-companion_2 %}
{% tab 'Scala 3 Only' %}
~~~ scala
val fooCtr: (Int, Boolean) => Foo = (x, b) => Foo(x, b)

fooCtr.curried(1)(true)
fooCtr.tupled((2, false))
```
~~~
{% endtab %}
{% endtabs %}
## Explicit Call to `unapply`

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

Given the following case class definition:

```scala
{% tabs shared-unapply_1 %}
{% tab 'Scala 2 and 3' %}
~~~ scala
case class Location(lat: Double, long: Double)
```
~~~
{% endtab %}
{% endtabs %}

The Scala 2.13 compiler generates the following `unapply` method:

```scala
{% tabs scala-2-unapply_2 %}
{% tab 'Scala 2 Only' %}
~~~ scala
object Location {
def unapply(location: Location): Option[(Double, Double)] = Some((location.lat, location.long))
}
```
~~~
{% endtab %}
{% endtabs %}

Whereas the Scala 3 compiler generates:

```scala
{% tabs scala-3-unapply_2 %}
{% tab 'Scala 3 Only' %}
~~~ scala
object Location {
def unapply(location: Location): Location = location
}
```

Consequently the following code does not compile anymore.

```scala
~~~
{% endtab %}
{% endtabs %}

Consequently the following code does not compile anymore in Scala 3.
{% tabs scala-2-unapply_3 %}
{% tab 'Scala 2 Only' %}
~~~ scala
def tuple(location: Location): (Int, Int) = {
Location.unapply(location).get // [E008] Not Found Error: value get is not a member of Location
Location.unapply(location).get // [E008] In Scala 3, Not Found Error: value get is not a member of Location
}
```
~~~
{% endtab %}
{% endtabs %}

A possible solution is to use pattern binding:
A possible solution, in Scala 3, is to use pattern binding:

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

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.

For instance, in the below example:

```scala
For instance, the below Scala 2 code would fail to compile in Scala 3:
{% tabs scala-2-bean_1 %}
{% tab 'Scala 2 Only' %}
~~~ scala
class Pojo() {
@BeanProperty var fooBar: String = ""
}

val pojo = new Pojo()

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

println(pojo.getFooBar()) // [E008] Not Found Error: value getFooBar is not a member of Pojo
```
println(pojo.getFooBar()) // [E008] In Scala 3, Not Found Error: value getFooBar is not a member of Pojo
~~~
{% endtab %}
{% endtabs %}

The solution is to call the more idiomatic `pojo.fooBar` getter and setter.
In Scala 3, the solution is to call the more idiomatic `pojo.fooBar` getter and setter.

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

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`.

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

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

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

For instance, the following example does not compile.

```scala
For instance, the below Scala 2 code would fail to compile in Scala 3:
{% tabs scala-2-wildcard_1 %}
{% tab 'Scala 2 Only' %}
~~~ scala
trait Example {
type Foo[A]

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

We can fix this by using a type parameter:

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

But this simple solution does not work when `Foo` is itself used as a type argument.

```scala
{% tabs scala-2-wildcard_2 %}
{% tab 'Scala 2 Only' %}
~~~ scala
def g(foos: Seq[Foo[_]]): Unit
```
~~~
{% endtab %}
{% endtabs %}

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

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

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