Skip to content

Commit e30781d

Browse files
committed
More details on implicit conversions
1 parent 0fcbfdb commit e30781d

File tree

1 file changed

+94
-30
lines changed

1 file changed

+94
-30
lines changed
Lines changed: 94 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,113 @@
11
---
22
layout: doc-page
3-
title: "Restrictions to Implicit Conversions"
3+
title: "Implicit Conversions - More Details"
44
---
55

6-
Previously, an implicit value of type `Function1`, or any of its subtypes
7-
could be used as an implicit conversion. That is, the following code would compile
8-
even though it probably masks a type error:
6+
## Implementation
97

10-
implicit val m: Map[Int, String] = Map(1 -> "abc")
8+
An implicit conversion, or _view_, from type `S` to type `T` is
9+
defined by either:
1110

12-
val x: String = 1 // scalac: assigns "abc" to x
13-
// Dotty: type error
11+
- An `implicit def` which has type `S => T` or `(=> S) => T`
12+
- An implicit value which has type `ImplicitConverter[S, T]`
1413

15-
By contrast, Dotty only considers _methods_ as implicit conversions, so the
16-
`Map` value `m` above would not qualify as a conversion from `String` to `Int`.
14+
The standard library defines an abstract class `ImplicitConverter`:
1715

18-
To be able to express implicit conversions passed as parameters, `Dotty`
19-
introduces a new type
16+
```scala
17+
abstract class ImplicitConverter[-T, +U] extends Function1[T, U]
18+
```
2019

21-
abstract class ImplicitConverter[-T, +U] extends Function1[T, U]
20+
Function literals are automatically converted to `ImplicitConverter`
21+
values.
2222

23-
Implicit values of type `ImplicitConverter[A, B]` do qualify as implicit
24-
conversions. It is as if there was a global implicit conversion method
23+
Views are applied in three situations:
2524

26-
def convert[A, B](x: A)(implicit converter: ImplicitConverter[A, B]): B =
27-
converter(x)
25+
1. If an expression `e` is of type `T`, and `T` does not conform to
26+
the expression's expected type `pt`. In this case, an implicit `v`
27+
which is applicable to `e` and whose result type conforms to `pt`
28+
is searched. The search proceeds as in the case of implicit
29+
parameters, where the implicit scope is the one of `T => pt`. If
30+
such a view is found, the expression `e` is converted to `v(e)`.
31+
1. In a selection `e.m` with `e` of type `T`, if the selector `m` does
32+
not denote an accessible member of `T`. In this case, a view `v`
33+
which is applicable to `e` and whose result contains an accessible
34+
member named `m` is searched. The search proceeds as in the case of
35+
implicit parameters, where the implicit scope is the one of `T`. If
36+
such a view is found, the selection `e.m` is converted to `v(e).m`.
37+
1. In an application `e.m(args)` with `e` of type `T`, if the selector
38+
`m` denotes some accessible member(s) of `T`, but none of these
39+
members is applicable to the arguments `args`. In this case, a view
40+
`v` which is applicable to `e` and whose result contains a method
41+
`m` which is applicable to `args` is searched. The search proceeds
42+
as in the case of implicit parameters, where the implicit scope is
43+
the one of `T`. If such a view is found, the application
44+
`e.m(args)` is converted to `v(e).m(args)`.
2845

29-
(In reality the Dotty compiler simulates the behavior of this method directly in
30-
its type checking because this turns out to be more efficient).
46+
# Differences with Scala 2 implicit conversions
3147

32-
In summary, previous code using implicit conversion parameters such as
48+
In Scala 2, views whose parameters are passed by-value take precedence
49+
over views whose parameters are passed by-name. This is no longer the
50+
case in Scala 3. A type error reporting the ambiguous conversions will
51+
be emitted in cases where this rule would be applied in Scala 2.
3352

34-
def useConversion(implicit f: A => B) = {
35-
val y: A = ...
36-
val x: B = y // error under Dotty
37-
}
53+
In Scala 2, implicit values of a function type would be considered as
54+
potential views. In Scala 3, these implicit value need to have type
55+
`ImplicitConverter`:
3856

39-
is no longer legal and has to be rewritten to
57+
```scala
58+
// Scala 2:
59+
def foo(x: Int)(implicit conv: Int => String): String = x
4060

41-
def useConversion(implicit f: ImplicitConverter[A, B]) = {
42-
val y: A = ...
43-
val x: B = y // OK
44-
}
61+
// Becomes with Scala 3:
62+
def foo(x: Int)(implicit conv: ImplicitConverter[Int, String]): String = x
4563

46-
### Reference
64+
// Call site is unchanged:
65+
foo(4)(_.toString)
4766

48-
For more info, see [PR #2065](https://github.com/lampepfl/dotty/pull/2065).
67+
// Scala 2:
68+
implicit val myConverter: Int => String = _.toString
69+
70+
// Becomes with Scala 3:
71+
implicit val myConverter: ImplicitConverter[Int, String] = _.toString
72+
```
73+
74+
Note that implicit conversions are also affected by the [changes to
75+
implicit resolution](implicit-resolution.html) between Scala 2 and
76+
Scala 3.
77+
78+
## Motivation for the changes
79+
80+
The introduction of `ImplicitConverter` in Scala 3 and the decision to
81+
restrict implicit values of this type to be considered as potential
82+
views comes from the desire to remove surprising behavior from the
83+
language:
84+
85+
```scala
86+
implicit val m: Map[Int, String] = Map(1 -> "abc")
87+
88+
val x: String = 1 // scalac: assigns "abc" to x
89+
// Dotty: type error
90+
```
91+
92+
This snippet contains a type error. The right hand side of `val x`
93+
does not conform to type `String`. In Scala 2, the compiler will use
94+
`m` as an implicit conversion from `Int` to `String`, whereas Scala 3
95+
will report a type error, because Map isn't an instance of
96+
`ImplicitConverter`.
97+
98+
## Migration path
99+
100+
Implicit values that are used as views should see their type changed
101+
to `ImplicitConverter`.
102+
103+
For the migration of implicit conversions that are affected by the
104+
changes to implicit resolution, refer to the [Changes in Implicit
105+
Resolution](implicit-resolution.html) for more information.
106+
107+
## Reference
108+
109+
For more information about implicit resolution, see [Changes in
110+
Implicit Resolution](implicit-resolution.html).
111+
Other details are available in
112+
[PR #2065](https://github.com/lampepfl/dotty/pull/2065)
49113

0 commit comments

Comments
 (0)