Skip to content

Add code tabs to contextual abstractions page #2724

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 2 commits into from
Mar 31, 2023
Merged
Changes from all 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
44 changes: 30 additions & 14 deletions _overviews/scala3-migration/incompat-contextual-abstractions.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,25 +27,31 @@ The Scalafix rule named `ExplicitImplicitTypes` in [ohze/scala-rewrites](https:/

Scala 3 does not support implicit conversion from an implicit function value, of the form `implicit val ev: A => B`.

The following piece of code is now invalid:
{% tabs scala-2-implicit_1 %}
{% tab 'Scala 2 Only' %}

```scala
The following piece of code is now invalid in Scala 3:
~~~ scala
trait Pretty {
val print: String
}

def pretty[A](a: A)(implicit ev: A => Pretty): String =
a.print // Error: value print is not a member of A
```
a.print // In Scala 3, Error: value print is not a member of A
~~~
{% endtab %}
{% endtabs %}

The [Scala 3 migration compilation](tooling-migration-mode.html) can warn you about those cases, but it does not try to fix it.

Be aware that this incompatibility can produce a runtime incompatibility and break your program.
Indeed the compiler can find another implicit conversion from a broader scope, which would eventually cause an undesired behavior at runtime.

This example illustrates the case:
{% tabs shared-implicit_2 %}
{% tab 'Scala 2 and 3' %}

```scala
This example illustrates the case:
~~~ scala
trait Pretty {
val print: String
}
Expand All @@ -54,13 +60,15 @@ implicit def anyPretty(any: Any): Pretty = new Pretty { val print = "any" }

def pretty[A](a: A)(implicit ev: A => Pretty): String =
a.print // always print "any"
```
~~~
{% endtab %}
{% endtabs %}

The resolved conversion depends on the compiler mode:
- `-source:3.0-migration`: the compiler performs the `ev` conversion
- `-source:3.0`: the compiler cannot perform the `ev` conversion but it can perform the `anyPretty`, which is undesired

One simple fix is to supply the right conversion explicitly:
In Scala 3, one simple fix is to supply the right conversion explicitly:

{% highlight diff %}
def pretty[A](a: A)(implicit ev: A => Pretty): String =
Expand All @@ -73,11 +81,15 @@ def pretty[A](a: A)(implicit ev: A => Pretty): String =
View bounds have been deprecated for a long time but they are still supported in Scala 2.13.
They cannot be compiled with Scala 3 anymore.

```scala
{% tabs scala-2-bounds_1 %}
{% tab 'Scala 2 Only' %}
~~~ scala
def foo[A <% Long](a: A): Long = a
```
~~~
{% endtab %}
{% endtabs %}

In this example we get:
In this example, in Scala 3, we get this following error message:

{% highlight text %}
-- Error: src/main/scala/view-bound.scala:2:12
Expand All @@ -104,12 +116,16 @@ It is not the case in Scala 3 anymore, and leads to an ambiguous conversion.

For instance, in this example:

```scala
{% tabs scala-2-ambiguous_1 %}
{% tab 'Scala 2 Only' %}
~~~ scala
implicit def boolFoo(bool: Boolean): Foo = ???
implicit def lazyBoolFoo(lazyBool: => Boolean): Foo = ???

true.foo()
```
~~~
{% endtab %}
{% endtabs %}

The Scala 2.13 compiler chooses the `boolFoo` conversion but the Scala 3 compiler fails to compile.

Expand All @@ -131,4 +147,4 @@ implicit def lazyBoolFoo(lazyBool: => Boolean): Foo = ???

-true.foo()
+boolFoo(true).foo()
{% endhighlight %}
{% endhighlight %}