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 1 commit
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
Prev Previous commit
Next Next commit
Corrections of the tabs.
Corrections of the tabs.

- Change scala 3 only by scala 2 only
- Re-add highlight parts

Delete Darwin dependencies
  • Loading branch information
Dedelweiss committed Mar 10, 2023
commit 14338888e0ddf2a44efb18242108c70d7a47355b
145 changes: 56 additions & 89 deletions _overviews/scala3-migration/incompat-other-changes.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,8 @@ 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.

{% tabs scala-3-abstract_1 %}
{% tab 'Scala 3 Only' %}
{% tabs scala-2-abstract_1 %}
{% tab 'Scala 2 Only' %}

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
Expand All @@ -121,7 +121,7 @@ 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
~~~

This behavior was decided in [Dotty issue #4770](https://github.com/lampepfl/dotty/issues/4770).
Expand All @@ -135,8 +135,8 @@ An easy fix is simply to remove the abstract def, since in practice it had no ef
The companion object of a case class does not extend any of the `Function{0-23}` traits anymore.
In particular, it does not inherit their methods: `tupled`, `curried`, `andThen`, `compose`...

{% tabs companion_1 class=tabs-scala-version %}
{% tab 'Scala 2' for=companion_1 %}
{% tabs scala-2-companion_1 %}
{% tab 'Scala 2 Only' %}

For instance, this is not permitted anymore:
~~~ scala
Expand All @@ -146,21 +146,23 @@ Foo.curried(1)(true)
Foo.tupled((2, false))
~~~
{% endtab %}
{% tab 'Scala 3' for=companion_1 %}
{% endtabs %}

A cross-compiling solution is to explicitly eta-expand the method `Foo.apply`.
~~~ scala
case class Foo(x: Int, b: Boolean)
{% highlight diff %}

(Foo.apply _).curried(1)(true)
(Foo.apply _).tupled((2, false))
~~~
-Foo.curried(1)(true)
+(Foo.apply _).curried(1)(true)

Or, for performance reasons, you can introduce an intermediate function value.
-Foo.tupled((2, false))
+(Foo.apply _).tupled((2, false))
{% endhighlight %}

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

Or, for performance reasons, you can introduce an intermediate function value.
~~~ scala
val fooCtr: (Int, Boolean) => Foo = (x, b) => Foo(x, b)

fooCtr.curried(1)(true)
Expand Down Expand Up @@ -208,45 +210,39 @@ object Location {
def unapply(location: Location): Location = location
}
~~~

Consequently the following code does not compile anymore.
~~~ scala
def tuple(location: Location): (Int, Int) = {
Location.unapply(location).get // [E008] Not Found Error: value get is not a member of Location
}
~~~
{% endtab %}
{% endtabs %}

A possible solution is to use pattern binding:

{% tabs unaply_3 class=tabs-scala-version %}
{% tab 'Scala 2' for=unaply_3 %}
{% tabs scala-2-unapply_3 %}
{% tab 'Scala 2 Only' %}

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

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

{% highlight diff %}
def tuple(location: Location): (Int, Int) = {
val Location(lat, lon) = location
(lat, lon)
- Location.unapply(location).get
+ val Location(lat, lon) = location
+ (lat, lon)
}
~~~
{% endtab %}
{% endtabs %}
{% endhighlight %}

## Invisible Bean Property

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.

{% tabs scala-3-bean_1 %}
{% tab 'Scala 3 Only' %}
{% tabs scala-2-bean_1 %}
{% tab 'Scala 2 Only' %}

For instance, in the below example:
For instance, the below Scala 2 code would fail to compile in Scala 3:

~~~ scala
class Pojo() {
Expand All @@ -255,36 +251,24 @@ class Pojo() {

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.

{% tabs bean_2 class=tabs-scala-version %}
{% tab 'Scala 2' for=bean_2 %}
In Scala 3, the solution is to call the more idiomatic `pojo.fooBar` getter and setter.

~~~ scala
val pojo = new Pojo()

pojo.setFooBar("hello")

println(pojo.getFooBar())
~~~
{% endtab %}
{% tab 'Scala 3' for=bean_2 %}
~~~ scala
{% highlight diff %}
val pojo = new Pojo()

pojo.fooBar = "hello"
-pojo.setFooBar("hello")
+pojo.fooBar = "hello"

println(pojo.fooBar)
~~~
{% endtab %}
{% endtabs %}
-println(pojo.getFooBar())
+println(pojo.fooBar)
{% endhighlight %}

## `=> T` as Type Argument

Expand Down Expand Up @@ -315,40 +299,31 @@ 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.

{% tabs scala-3-wildcard_1 %}
{% tab 'Scala 3 Only' %}
{% tabs scala-2-wildcard_1 %}
{% tab 'Scala 2 Only' %}

For instance, the following example does not compile.
For instance, the below Scala 2 code would fail to compile in Scala 3:

~~~ 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:

{% tabs wildcard_2 class=tabs-scala-version %}
{% tab 'Scala 2' for=wildcard_2 %}

~~~ scala
def f(foo: Foo[_]): Unit
~~~
{% endtab %}
{% tab 'Scala 3' for=wildcard_2 %}
~~~ scala
def f[A](foo: Foo[A]): Unit
~~~
{% endtab %}
{% endtabs %}
{% highlight diff %}
-def f(foo: Foo[_]): Unit
+def f[A](foo: Foo[A]): Unit
{% endhighlight %}

But this simple solution does not work when `Foo` is itself used as a type argument.
{% tabs shared-wildcard_3 %}
{% tab 'Scala 2 and 3' %}
{% tabs scala-2-wildcard_2 %}
{% tab 'Scala 2 Only' %}
~~~ scala
def g(foos: Seq[Foo[_]]): Unit
~~~
Expand All @@ -357,17 +332,9 @@ def g(foos: Seq[Foo[_]]): Unit

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

{% tabs wildcard_4 class=tabs-scala-version %}
{% tab 'Scala 2' for=wildcard_4 %}
~~~ scala
def g(foos: Seq[Foo[_]]): Unit
~~~
{% endtab %}
{% tab 'Scala 3' for=wildcard_4 %}
~~~ scala
class FooWrapper[A](foo: Foo[A])
{% highlight diff %}
+class FooWrapper[A](foo: Foo[A])

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