Skip to content

Commit 4b7a29d

Browse files
authored
Merge pull request #6483 from dotty-staging/change-contextual-implicits
Tweaks to implicit and repr variants of doc pages
2 parents b22cf06 + abceed6 commit 4b7a29d

15 files changed

+70
-70
lines changed

docs/docs/reference/contextual-implicit/conversions.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,9 @@ object Completions {
5959
//
6060
// CompletionArg.fromStatusCode(statusCode)
6161

62-
implicit fromString for Conversion[String, CompletionArg] = Error(_)
63-
implicit fromFuture for Conversion[Future[HttpResponse], CompletionArg] = Response(_)
64-
implicit fromStatusCode for Conversion[Future[StatusCode], CompletionArg] = Status(_)
62+
implicit fromString for Conversion[String, CompletionArg] = Error(_)
63+
implicit fromFuture for Conversion[Future[HttpResponse], CompletionArg] = Response(_)
64+
implicit fromStatusCode for Conversion[Future[StatusCode], CompletionArg] = Status(_)
6565
}
6666
import CompletionArg._
6767

docs/docs/reference/contextual-implicit/derivation.md

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,18 @@ layout: doc-page
33
title: Typeclass Derivation
44
---
55

6-
Typeclass derivation is a way to generate instances of certain type classes automatically or with minimal code hints. A type class in this sense is any trait or class with a type parameter that describes the type being operated on. Commonly used examples are `Eql`, `Ordering`, `Show`, or `Pickling`. Example:
6+
Typeclass derivation is a way to generate implicit instances for certain type classes automatically or with minimal code hints. A type class in this sense is any trait or class with a type parameter that describes the type being operated on. Commonly used examples are `Eql`, `Ordering`, `Show`, or `Pickling`. Example:
77
```scala
88
enum Tree[T] derives Eql, Ordering, Pickling {
99
case Branch(left: Tree[T], right: Tree[T])
1010
case Leaf(elem: T)
1111
}
1212
```
13-
The `derives` clause generates implicits for the `Eql`, `Ordering`, and `Pickling` traits in the companion object `Tree`:
13+
The `derives` clause generates implicit instances for the `Eql`, `Ordering`, and `Pickling` traits in the companion object `Tree`:
1414
```scala
15-
implicit [T: Eql] for Eql[Tree[T]] = Eql.derived
16-
implicit [T: Ordering] for Ordering[Tree[T]] = Ordering.derived
17-
implicit [T: Pickling] for Pickling[Tree[T]] = Pickling.derived
15+
implicit [T: Eql] for Eql[Tree[T]] = Eql.derived
16+
implicit [T: Ordering] for Ordering[Tree[T]] = Ordering.derived
17+
implicit [T: Pickling] for Pickling[Tree[T]] = Pickling.derived
1818
```
1919

2020
### Deriving Types
@@ -42,8 +42,7 @@ A trait or class can appear in a `derives` clause if its companion object define
4242
```scala
4343
def derived[T] given Generic[T] = ...
4444
```
45-
That is, the `derived` method takes an implicit parameter of type `Generic` that determines the _shape_ of the deriving type `T` and it computes the typeclass implementation according to that shape. Implicits for `Generic` are generated automatically for any type that derives a typeclass with a `derived`
46-
method that refers to `Generic`. One can also derive `Generic` alone, which means a `Generic` instance is generated without any other type class instances. E.g.:
45+
That is, the `derived` method takes an implicit parameter of type `Generic` that determines the _shape_ of the deriving type `T` and it computes the typeclass implementation according to that shape. An implicit `Generic` instance is generated automatically for any type that derives a typeclass with a `derived` method that refers to `Generic`. One can also derive `Generic` alone, which means a `Generic` instance is generated without any other type class instances. E.g.:
4746
```scala
4847
sealed trait ParseResult[T] derives Generic
4948
```
@@ -94,7 +93,7 @@ is represented as `T *: Unit` since there is no direct syntax for such tuples: `
9493

9594
### The Generic Typeclass
9695

97-
For every class `C[T_1,...,T_n]` with a `derives` clause, the compiler generates in the companion object of `C` an implicit for `Generic[C[T_1,...,T_n]]` that follows the outline below:
96+
For every class `C[T_1,...,T_n]` with a `derives` clause, the compiler generates in the companion object of `C` an implicit instance for `Generic[C[T_1,...,T_n]]` that follows the outline below:
9897
```scala
9998
implicit [T_1, ..., T_n] for Generic[C[T_1,...,T_n]] {
10099
type Shape = ...
@@ -214,8 +213,8 @@ trait Eql[T] {
214213
def eql(x: T, y: T): Boolean
215214
}
216215
```
217-
We need to implement a method `Eql.derived` that produces an implicit value of type `Eql[T]` provided
218-
there exists an implicit value of type `Generic[T]`. Here's a possible solution:
216+
We need to implement a method `Eql.derived` that produces an implicit instance of type `Eql[T]` provided
217+
there exists an implicit instance of type `Generic[T]`. Here's a possible solution:
219218
```scala
220219
inline def derived[T] given (ev: Generic[T]): Eql[T] = new Eql[T] {
221220
def eql(x: T, y: T): Boolean = {
@@ -333,21 +332,22 @@ implicit [T] for Eql[Tree[T]] given (elemEq: Eql[T]) {
333332
}
334333
```
335334

336-
One important difference between this approach and Scala-2 typeclass derivation frameworks such as Shapeless or Magnolia is that no automatic attempt is made to generate typeclass instances of elements recursively using the generic derivation framework. There must be an implicit value of type `Eql[T]` (which can of course be produced in turn using `Eql.derived`), or the compilation will fail. The advantage of this more restrictive approach to typeclass derivation is that it avoids uncontrolled transitive typeclass derivation by design. This keeps code sizes smaller, compile times lower, and is generally more predictable.
335+
One important difference between this approach and Scala-2 typeclass derivation frameworks such as Shapeless or Magnolia is that no automatic attempt is made to generate typeclass instances of elements recursively using the generic derivation framework. There must be an implicit instance of type `Eql[T]` (which can of course be produced in turn using `Eql.derived`), or the compilation will fail. The advantage of this more restrictive approach to typeclass derivation is that it avoids uncontrolled transitive typeclass derivation by design. This keeps code sizes smaller, compile times lower, and is generally more predictable.
337336

338-
### Derived Instances Elsewhere
337+
### Deriving Instances Elsewhere
339338

340339
Sometimes one would like to derive a typeclass instance for an ADT after the ADT is defined, without being able to change the code of the ADT itself.
341-
To do this, simply define an instance with the `derived` method of the typeclass as right-hand side. E.g, to implement `Ordering` for `Option`, define:
340+
To do this, simply define an implicit instance with the `derived` method of the typeclass as right-hand side. E.g, to implement `Ordering` for `Option`, define:
342341
```scala
343-
implicit [T: Ordering]: Ordering[Option[T]] = Ordering.derived
342+
implicit [T: Ordering] for Ordering[Option[T]] = Ordering.derived
344343
```
345344
Usually, the `Ordering.derived` clause has an implicit parameter of type
346345
`Generic[Option[T]]`. Since the `Option` trait has a `derives` clause,
347-
the necessary implicit is already present in the companion object of `Option`.
348-
If the ADT in question does not have a `derives` clause, an implicit for `Generic`
346+
the necessary implicit instance is already present in the companion object of `Option`.
347+
If the ADT in question does not have a `derives` clause, an implicit instance for `Generic`
349348
would still be synthesized by the compiler at the point where `derived` is called.
350-
This is similar to the situation with type tags or class tags: If no implicit is found, the compiler will synthesize it.
349+
This is similar to the situation with type tags or class tags: If no implicit instance is found,
350+
the compiler will synthesize one.
351351

352352
### Syntax
353353

docs/docs/reference/contextual-implicit/extension-methods.md

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ When is an extension method applicable? There are two possibilities.
3636

3737
- An extension method is applicable if it is visible under a simple name, by being defined
3838
or inherited or imported in a scope enclosing the application.
39-
- An extension method is applicable if it is a member of some implicit value at the point of the application.
39+
- An extension method is applicable if it is a member of some implicit instance at the point of the application.
4040

4141
As an example, consider an extension method `longestStrings` on `String` defined in a trait `StringSeqOps`.
4242

@@ -48,7 +48,7 @@ trait StringSeqOps {
4848
}
4949
}
5050
```
51-
We can make the extension method available by defining an implicit for `StringSeqOps`, like this:
51+
We can make the extension method available by defining an implicit instance for `StringSeqOps`, like this:
5252
```scala
5353
implicit ops1 for StringSeqOps
5454
```
@@ -76,7 +76,7 @@ and where `T` is the expected type. The following two rewritings are tried in or
7676
from `T` to a type containing `m`. If there is more than one way of rewriting, an ambiguity error results.
7777

7878
So `circle.circumference` translates to `CircleOps.circumference(circle)`, provided
79-
`circle` has type `Circle` and `CircleOps` is an eligible implicit value (i.e. it is visible at the point of call or it is defined in the companion object of `Circle`).
79+
`circle` has type `Circle` and `CircleOps` is an eligible implicit (i.e. it is visible at the point of call or it is defined in the companion object of `Circle`).
8080

8181
### Implicits for Extension Methods
8282

@@ -144,7 +144,3 @@ to the [current syntax](https://github.com/lampepfl/dotty/blob/master/docs/docs/
144144
DefSig ::= ...
145145
| ‘(’ DefParam ‘)’ [nl] id [DefTypeParamClause] DefParamClauses
146146
```
147-
148-
149-
150-

docs/docs/reference/contextual-implicit/import-implied.md

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ layout: doc-page
33
title: "Import Implicit"
44
---
55

6-
A special form of import is used to import implicit values. Example:
6+
A special form of import is used to import implicit instances. Example:
77
```scala
88
object A {
99
class TC
@@ -16,16 +16,16 @@ object B {
1616
}
1717
```
1818
In the code above, the `import A._` clause of object `B` will import all members
19-
of `A` _except_ the implicit `tc`. Conversely, the second import `import implicit A._` will import _only_ that implicit.
19+
of `A` _except_ the implicit `tc`. Conversely, the second import `import implicit A._` will import _only_ that implicit instance.
2020

21-
Generally, a normal import clause brings all members except implicit values into scope whereas an `import implicit` clause brings only implicit values into scope.
21+
Generally, a normal import clause brings all members except implicit instances into scope whereas an `import implicit` clause brings only implicit instances into scope.
2222

2323
There are two main benefits arising from these rules:
2424

25-
- It is made clearer where implicit values in scope are coming from. In particular, it is not possible to hide imported implicit values in a long list of regular imports.
26-
- It enables importing all implicit values
25+
- It is made clearer where implicit instances in scope are coming from. In particular, it is not possible to hide imported implicit instances in a long list of regular imports.
26+
- It enables importing all implicit instances
2727
without importing anything else. This is particularly important since implicit
28-
values can be anonymous, so the usual recourse of using named imports is not
28+
instances can be anonymous, so the usual recourse of using named imports is not
2929
practical.
3030

3131
### Migration
@@ -41,6 +41,8 @@ To make gradual migration possible, we adapt the following scheme.
4141
3. In some version after 3.1, an old-style implicit accessed implicitly through a normal import
4242
will give a compiler error.
4343

44+
New-style implicit instance definitions always need to be imported with `import implicit`.
45+
4446
These rules mean that library users can use `import implicit` to access old-style implicits in Scala 3.0,
4547
and will be gently nudged and then forced to do so in later versions. Libraries can then switch to
4648
new-style implicit definitions once their user base has migrated.

docs/docs/reference/contextual-implicit/inferable-by-name-parameters.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,14 @@ if this is necessary to prevent an otherwise diverging expansion.
3333

3434
The precise steps for synthesizing an argument for a by-name parameter of type `=> T` are as follows.
3535

36-
1. Create a new implicit for type `T`:
36+
1. Create a new implicit instance for type `T`:
3737

3838
```scala
3939
implicit lv for T = ???
4040
```
4141
where `lv` is an arbitrary fresh name.
4242

43-
1. This implicit is not immediately available as a candidate for argument inference (making it immediately available could result in a loop in the synthesized computation). But it becomes available in all nested contexts that look again for an implicit argument to a by-name parameter.
43+
1. This instance is not immediately available as a candidate implicit (making it immediately available could result in a loop in the synthesized computation). But it becomes available in all nested contexts that look again for an implicit argument to a by-name parameter.
4444

4545
1. If this search succeeds with expression `E`, and `E` contains references to the implicit `lv`, replace `E` by
4646

docs/docs/reference/contextual-implicit/inferable-params.md

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,16 @@ max(List(1, 2, 3), Nil)
3030

3131
## Anonymous Implicit Parameters
3232

33-
In many situations, the name of an implicit parameter of a method need not be mentioned explicitly at all, since it is only used as a synthesized argument for other implicit parameters. In that case one can avoid defining a parameter name and just provide its type. Example:
33+
In many situations, the name of an implicit parameter of a method need not be
34+
mentioned explicitly at all, since it is only used in synthesized arguments for
35+
other implicit parameters. In that case one can avoid defining a parameter name
36+
and just provide its type. Example:
3437
```scala
3538
def maximum[T](xs: List[T]) given Ord[T]: T =
3639
xs.reduceLeft(max)
3740
```
38-
`maximum` takes an implicit parameter of type `Ord` only to pass it on as an implicit argument to `max`. The name of the parameter is left out.
41+
`maximum` takes an implicit parameter of type `Ord` only to pass it on as a
42+
synthesized argument to `max`. The name of the parameter is left out.
3943

4044
Generally, implicit parameters may be given either as a parameter list `(p_1: T_1, ..., p_n: T_n)`
4145
or as a sequence of types, separated by commas.
@@ -79,9 +83,9 @@ f("abc").given(ctx)
7983
f.given(global)("abc").given(ctx)
8084
```
8185

82-
## Summoning an Implicit
86+
## Summoning Implicit Instances
8387

84-
A method `the` in `Predef` returns an implicit instance of a given type. For example, the implicit for `Ord[List[Int]]` is generated by
88+
A method `the` in `Predef` returns an implicit instance for a given type. For example, the implicit for `Ord[List[Int]]` is generated by
8589
```scala
8690
the[Ord[List[Int]]] // reduces to ListOrd given IntOrd
8791
```

docs/docs/reference/contextual-implicit/instance-defs.md

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ title: "Implicit Instances"
44
---
55

66
Implicit instances define "canonical" values of given types
7-
that can be synthesized by the compiler. Typically, such values are
8-
used as arguments to [given clauses](./inferable-params.html). Example:
7+
that can be synthesized by the compiler as arguments for
8+
[given clauses](./inferable-params.html). Example:
99
```scala
1010
trait Ord[T] {
1111
def compare(x: T, y: T): Int
@@ -18,7 +18,7 @@ implicit IntOrd for Ord[Int] {
1818
if (x < y) -1 else if (x > y) +1 else 0
1919
}
2020

21-
implicit ListOrd[T] for Ord[List[T]] given (ord: Ord[T]){
21+
implicit ListOrd[T] for Ord[List[T]] given (ord: Ord[T]) {
2222
def compare(xs: List[T], ys: List[T]): Int = (xs, ys) match {
2323
case (Nil, Nil) => 0
2424
case (Nil, _) => -1
@@ -30,10 +30,10 @@ implicit ListOrd[T] for Ord[List[T]] given (ord: Ord[T]){
3030
}
3131
```
3232
This code defines a trait `Ord` and two implicit definitions. `IntOrd` defines
33-
an implicit value of the type `Ord[Int]` whereas `ListOrd[T]` defines implicit values of types `Ord[List[T]]`
34-
for all types `T` that come with implicit values for `Ord[T]` themselves.
35-
The `given` clause in `ListOrd` defines an [implicit parameter](./inferable-params.html).
36-
Given clauses are further explained in the next section.
33+
an implicit instance of the type `Ord[Int]` whereas `ListOrd[T]` defines implicit instances of type `Ord[List[T]]`
34+
for all types `T` that come with an implicit instance for `Ord[T]` themselves.
35+
The `given` clause in `ListOrd` defines an implicit parameter.
36+
Given clauses are further explained in the [next section](./inferable-params.html).
3737

3838
## Anonymous Implicit Instances
3939

@@ -43,12 +43,12 @@ of the last section can also be expressed like this:
4343
implicit for Ord[Int] { ... }
4444
implicit [T] for Ord[List[T]] given (ord: Ord[T]) { ... }
4545
```
46-
If the name of an implicit is missing, the compiler will synthesize a name from
46+
If the name of an implicit instance is missing, the compiler will synthesize a name from
4747
the type(s) in the `for` clause.
4848

4949
## Alias Implicits
5050

51-
An alias can be used to define an implicit value that is equal to some expression. E.g.:
51+
An alias can be used to define an implicit instance that is equal to some expression. E.g.:
5252
```scala
5353
implicit global for ExecutionContext = new ForkJoinPool()
5454
```
@@ -64,7 +64,7 @@ An alias implicit can have type and context parameters just like any other impli
6464

6565
## Implicit Instance Creation
6666

67-
An implicit instance without type parameters or given clause is created on-demand, the first time it is accessed. It is not required to ensure safe publication, which means that different threads might create different instances for the same `implicit` clause. If an `implicit` definition has type parameters or a given clause, a fresh instance is created for each reference.
67+
An implicit instance without type parameters or given clause is created on-demand, the first time it is accessed. It is not required to ensure safe publication, which means that different threads might create different instances for the same `implicit` definition. If an `implicit` definition has type parameters or a given clause, a fresh instance is created for each reference.
6868

6969
## Syntax
7070

docs/docs/reference/contextual-implicit/motivation.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,14 +53,14 @@ The following pages introduce a redesign of contextual abstractions in Scala. Th
5353

5454
3. [Import Implicit](./import-implied.html) is new form of import that specifically imports implicit definitions and nothing else. New-style implicit instances _must be_ imported with `import implicit`, a plain import will no longer bring them into scope. Old-style implicit definitions can be imported with either form.
5555

56-
4. [Implicit Conversions](./conversions.html) are now expressed as implicit values of a standard `Conversion` class. All other forms of implicit conversions will be phased out.
56+
4. [Implicit Conversions](./conversions.html) are now expressed as implicit instances of a standard `Conversion` class. All other forms of implicit conversions will be phased out.
5757

5858
This section also contains pages describing other language features that are related to context abstraction. These are:
5959

6060
- [Context Bounds](./context-bounds.html), which carry over unchanged.
6161
- [Extension Methods](./extension-methods.html) replace implicit classes in a way that integrates better with typeclasses.
6262
- [Implementing Typeclasses](./typeclasses.html) demonstrates how some common typeclasses can be implemented using the new constructs.
63-
- [Typeclass Derivation](./derivation.html) introduces constructs to automatically derive typeclasses for ADTs.
63+
- [Typeclass Derivation](./derivation.html) introduces constructs to automatically derive implicit typeclass instances for ADTs.
6464
- [Multiversal Equality](./multiversal-equality.html) introduces a special typeclass
6565
to support type safe equality.
6666
- [Implicit Function Types](./query-types.html) introduce a way to abstract over implicit parameterization.
@@ -79,4 +79,3 @@ Could we achieve the same goals by tweaking existing implicits? After having tri
7979
- Third, even if we would somehow succeed with migration, we still have the problem
8080
how to teach this. We cannot make existing tutorials go away. Almost all existing tutorials start with implicit conversions, which will go away; they use normal imports, which will go away, and they explain calls to methods with implicit parameters by expanding them to plain applications, which will also go away. This means that we'd have
8181
to add modifications and qualifications to all existing literature and courseware, likely causing more confusion with beginners instead of less. By contrast, with a new syntax there is a clear criterion: Any book or courseware that mentions `implicit` is outdated and should be updated.
82-

0 commit comments

Comments
 (0)