Skip to content

Commit 3bf5ba1

Browse files
committed
Correction of the tabs
- Change tabs title - Re-add Highlight diff and Highlight text
1 parent e3d594a commit 3bf5ba1

File tree

1 file changed

+35
-44
lines changed

1 file changed

+35
-44
lines changed

_overviews/scala3-migration/incompat-contextual-abstractions.md

+35-44
Original file line numberDiff line numberDiff line change
@@ -27,17 +27,17 @@ The Scalafix rule named `ExplicitImplicitTypes` in [ohze/scala-rewrites](https:/
2727

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

30-
{% tabs scala-3-implicit_1 %}
31-
{% tab 'Scala 3 Only' %}
30+
{% tabs scala-2-implicit_1 %}
31+
{% tab 'Scala 2 Only' %}
3232

33-
The following piece of code is now invalid:
33+
The following piece of code is now invalid in Scala 3:
3434
~~~ scala
3535
trait Pretty {
3636
val print: String
3737
}
3838

3939
def pretty[A](a: A)(implicit ev: A => Pretty): String =
40-
a.print // Error: value print is not a member of A
40+
a.print // In Scala 3, Error: value print is not a member of A
4141
~~~
4242
{% endtab %}
4343
{% endtabs %}
@@ -47,8 +47,8 @@ The [Scala 3 migration compilation](tooling-migration-mode.html) can warn you ab
4747
Be aware that this incompatibility can produce a runtime incompatibility and break your program.
4848
Indeed the compiler can find another implicit conversion from a broader scope, which would eventually cause an undesired behavior at runtime.
4949

50-
{% tabs scala-3-implicit_2 %}
51-
{% tab 'Scala 3 Only' %}
50+
{% tabs shared-implicit_2 %}
51+
{% tab 'Scala 2 and 3' %}
5252

5353
This example illustrates the case:
5454
~~~ scala
@@ -61,99 +61,90 @@ implicit def anyPretty(any: Any): Pretty = new Pretty { val print = "any" }
6161
def pretty[A](a: A)(implicit ev: A => Pretty): String =
6262
a.print // always print "any"
6363
~~~
64+
{% endtab %}
65+
{% endtabs %}
6466

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

69-
One simple fix is to supply the right conversion explicitly:
71+
In Scala 3, one simple fix is to supply the right conversion explicitly:
7072

71-
~~~ scala
73+
{% highlight diff %}
7274
def pretty[A](a: A)(implicit ev: A => Pretty): String =
73-
ev(a).print
74-
~~~
75-
{% endtab %}
76-
{% endtabs %}
75+
- a.print
76+
+ ev(a).print
77+
{% endhighlight %}
7778

7879
## View Bounds
7980

8081
View bounds have been deprecated for a long time but they are still supported in Scala 2.13.
8182
They cannot be compiled with Scala 3 anymore.
8283

83-
{% tabs scala-3-bounds_1 %}
84-
{% tab 'Scala 3 Only' %}
84+
{% tabs scala-2-bounds_1 %}
85+
{% tab 'Scala 2 Only' %}
8586
~~~ scala
8687
def foo[A <% Long](a: A): Long = a
8788
~~~
89+
{% endtab %}
90+
{% endtabs %}
8891

89-
In this example we get:
92+
In this example, in Scala 3, we get this following error message:
9093

91-
~~~ text
94+
{% highlight text %}
9295
-- Error: src/main/scala/view-bound.scala:2:12
9396
2 | def foo[A <% Long](a: A): Long = a
9497
| ^
9598
| view bounds `<%' are deprecated, use a context bound `:' instead
96-
~~~
97-
{% endtab %}
98-
{% endtabs %}
99+
{% endhighlight %}
99100

100101
The message suggests to use a context bound instead of a view bound but it would change the signature of the method.
101102
It is probably easier and safer to preserve the binary compatibility.
102103
To do so the implicit conversion must be declared and called explicitly.
103104

104105
Be careful not to fall in the runtime incompatibility described above, in [Implicit Views](#implicit-views).
105106

106-
{% tabs runtime_1 class=tabs-scala-version %}
107-
{% tab 'Scala 2' for=runtime_1 %}
108-
~~~ scala
109-
def foo[A <% Long](a: A): Long = a
110-
~~~
111-
112-
{% endtab %}
113-
{% tab 'Scala 3' for=runtime_1 %}
114-
~~~ scala
115-
def foo[A](a: A)(implicit ev: A => Long): Long = ev(a)
116-
~~~
117-
{% endtab %}
118-
{% endtabs %}
107+
{% highlight diff %}
108+
-def foo[A <% Long](a: A): Long = a
109+
+def foo[A](a: A)(implicit ev: A => Long): Long = ev(a)
110+
{% endhighlight %}
119111

120112
## Ambiguous Conversion On `A` And `=> A`
121113

122114
In Scala 2.13 the implicit conversion on `A` wins over the implicit conversion on `=> A`.
123115
It is not the case in Scala 3 anymore, and leads to an ambiguous conversion.
124116

125-
{% tabs ambiguous_1 class=tabs-scala-version %}
126-
{% tab 'Scala 2' for=ambiguous_1 %}
127-
128117
For instance, in this example:
118+
119+
{% tabs scala-2-ambiguous_1 %}
120+
{% tab 'Scala 2 Only' %}
129121
~~~ scala
130122
implicit def boolFoo(bool: Boolean): Foo = ???
131123
implicit def lazyBoolFoo(lazyBool: => Boolean): Foo = ???
132124

133125
true.foo()
134126
~~~
127+
{% endtab %}
128+
{% endtabs %}
135129

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

138-
~~~ text
132+
{% highlight text %}
139133
-- Error: src/main/scala/ambiguous-conversion.scala:4:19
140134
9 | true.foo()
141135
| ^^^^
142136
|Found: (true : Boolean)
143137
|Required: ?{ foo: ? }
144138
|Note that implicit extension methods cannot be applied because they are ambiguous;
145139
|both method boolFoo in object Foo and method lazyBoolFoo in object Foo provide an extension method `foo` on (true : Boolean)
146-
~~~
147-
{% endtab %}
148-
{% tab 'Scala 3' for=ambiguous_1 %}
140+
{% endhighlight %}
149141

150142
A temporary solution is to write the conversion explicitly.
151143

152-
~~~ scala
144+
{% highlight diff %}
153145
implicit def boolFoo(bool: Boolean): Foo = ???
154146
implicit def lazyBoolFoo(lazyBool: => Boolean): Foo = ???
155147

156-
boolFoo(true).foo()
157-
~~~
158-
{% endtab %}
159-
{% endtabs %}
148+
-true.foo()
149+
+boolFoo(true).foo()
150+
{% endhighlight %}

0 commit comments

Comments
 (0)