Skip to content

Tweaks to implicit and repr variants of doc pages #6483

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 1 commit into from
May 9, 2019
Merged
Show file tree
Hide file tree
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
6 changes: 3 additions & 3 deletions docs/docs/reference/contextual-implicit/conversions.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,9 @@ object Completions {
//
// CompletionArg.fromStatusCode(statusCode)

implicit fromString for Conversion[String, CompletionArg] = Error(_)
implicit fromFuture for Conversion[Future[HttpResponse], CompletionArg] = Response(_)
implicit fromStatusCode for Conversion[Future[StatusCode], CompletionArg] = Status(_)
implicit fromString for Conversion[String, CompletionArg] = Error(_)
implicit fromFuture for Conversion[Future[HttpResponse], CompletionArg] = Response(_)
implicit fromStatusCode for Conversion[Future[StatusCode], CompletionArg] = Status(_)
}
import CompletionArg._

Expand Down
34 changes: 17 additions & 17 deletions docs/docs/reference/contextual-implicit/derivation.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,18 @@ layout: doc-page
title: Typeclass Derivation
---

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:
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:
```scala
enum Tree[T] derives Eql, Ordering, Pickling {
case Branch(left: Tree[T], right: Tree[T])
case Leaf(elem: T)
}
```
The `derives` clause generates implicits for the `Eql`, `Ordering`, and `Pickling` traits in the companion object `Tree`:
The `derives` clause generates implicit instances for the `Eql`, `Ordering`, and `Pickling` traits in the companion object `Tree`:
```scala
implicit [T: Eql] for Eql[Tree[T]] = Eql.derived
implicit [T: Ordering] for Ordering[Tree[T]] = Ordering.derived
implicit [T: Pickling] for Pickling[Tree[T]] = Pickling.derived
implicit [T: Eql] for Eql[Tree[T]] = Eql.derived
implicit [T: Ordering] for Ordering[Tree[T]] = Ordering.derived
implicit [T: Pickling] for Pickling[Tree[T]] = Pickling.derived
```

### Deriving Types
Expand Down Expand Up @@ -42,8 +42,7 @@ A trait or class can appear in a `derives` clause if its companion object define
```scala
def derived[T] given Generic[T] = ...
```
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`
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.:
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.:
```scala
sealed trait ParseResult[T] derives Generic
```
Expand Down Expand Up @@ -94,7 +93,7 @@ is represented as `T *: Unit` since there is no direct syntax for such tuples: `

### The Generic Typeclass

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:
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:
```scala
implicit [T_1, ..., T_n] for Generic[C[T_1,...,T_n]] {
type Shape = ...
Expand Down Expand Up @@ -214,8 +213,8 @@ trait Eql[T] {
def eql(x: T, y: T): Boolean
}
```
We need to implement a method `Eql.derived` that produces an implicit value of type `Eql[T]` provided
there exists an implicit value of type `Generic[T]`. Here's a possible solution:
We need to implement a method `Eql.derived` that produces an implicit instance of type `Eql[T]` provided
there exists an implicit instance of type `Generic[T]`. Here's a possible solution:
```scala
inline def derived[T] given (ev: Generic[T]): Eql[T] = new Eql[T] {
def eql(x: T, y: T): Boolean = {
Expand Down Expand Up @@ -333,21 +332,22 @@ implicit [T] for Eql[Tree[T]] given (elemEq: Eql[T]) {
}
```

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.
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.

### Derived Instances Elsewhere
### Deriving Instances Elsewhere

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.
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:
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:
```scala
implicit [T: Ordering]: Ordering[Option[T]] = Ordering.derived
implicit [T: Ordering] for Ordering[Option[T]] = Ordering.derived
```
Usually, the `Ordering.derived` clause has an implicit parameter of type
`Generic[Option[T]]`. Since the `Option` trait has a `derives` clause,
the necessary implicit is already present in the companion object of `Option`.
If the ADT in question does not have a `derives` clause, an implicit for `Generic`
the necessary implicit instance is already present in the companion object of `Option`.
If the ADT in question does not have a `derives` clause, an implicit instance for `Generic`
would still be synthesized by the compiler at the point where `derived` is called.
This is similar to the situation with type tags or class tags: If no implicit is found, the compiler will synthesize it.
This is similar to the situation with type tags or class tags: If no implicit instance is found,
the compiler will synthesize one.

### Syntax

Expand Down
10 changes: 3 additions & 7 deletions docs/docs/reference/contextual-implicit/extension-methods.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ When is an extension method applicable? There are two possibilities.

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

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

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

So `circle.circumference` translates to `CircleOps.circumference(circle)`, provided
`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`).
`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`).

### Implicits for Extension Methods

Expand Down Expand Up @@ -144,7 +144,3 @@ to the [current syntax](https://github.com/lampepfl/dotty/blob/master/docs/docs/
DefSig ::= ...
| ‘(’ DefParam ‘)’ [nl] id [DefTypeParamClause] DefParamClauses
```




14 changes: 8 additions & 6 deletions docs/docs/reference/contextual-implicit/import-implied.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ layout: doc-page
title: "Import Implicit"
---

A special form of import is used to import implicit values. Example:
A special form of import is used to import implicit instances. Example:
```scala
object A {
class TC
Expand All @@ -16,16 +16,16 @@ object B {
}
```
In the code above, the `import A._` clause of object `B` will import all members
of `A` _except_ the implicit `tc`. Conversely, the second import `import implicit A._` will import _only_ that implicit.
of `A` _except_ the implicit `tc`. Conversely, the second import `import implicit A._` will import _only_ that implicit instance.

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

There are two main benefits arising from these rules:

- 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.
- It enables importing all implicit values
- 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.
- It enables importing all implicit instances
without importing anything else. This is particularly important since implicit
values can be anonymous, so the usual recourse of using named imports is not
instances can be anonymous, so the usual recourse of using named imports is not
practical.

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

New-style implicit instance definitions always need to be imported with `import implicit`.

These rules mean that library users can use `import implicit` to access old-style implicits in Scala 3.0,
and will be gently nudged and then forced to do so in later versions. Libraries can then switch to
new-style implicit definitions once their user base has migrated.
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,14 @@ if this is necessary to prevent an otherwise diverging expansion.

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

1. Create a new implicit for type `T`:
1. Create a new implicit instance for type `T`:

```scala
implicit lv for T = ???
```
where `lv` is an arbitrary fresh name.

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.
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.

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

Expand Down
12 changes: 8 additions & 4 deletions docs/docs/reference/contextual-implicit/inferable-params.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,16 @@ max(List(1, 2, 3), Nil)

## Anonymous Implicit Parameters

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:
In many situations, the name of an implicit parameter of a method need not be
mentioned explicitly at all, since it is only used in synthesized arguments for
other implicit parameters. In that case one can avoid defining a parameter name
and just provide its type. Example:
```scala
def maximum[T](xs: List[T]) given Ord[T]: T =
xs.reduceLeft(max)
```
`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.
`maximum` takes an implicit parameter of type `Ord` only to pass it on as a
synthesized argument to `max`. The name of the parameter is left out.

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

## Summoning an Implicit
## Summoning Implicit Instances

A method `the` in `Predef` returns an implicit instance of a given type. For example, the implicit for `Ord[List[Int]]` is generated by
A method `the` in `Predef` returns an implicit instance for a given type. For example, the implicit for `Ord[List[Int]]` is generated by
```scala
the[Ord[List[Int]]] // reduces to ListOrd given IntOrd
```
Expand Down
20 changes: 10 additions & 10 deletions docs/docs/reference/contextual-implicit/instance-defs.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ title: "Implicit Instances"
---

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

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

## Anonymous Implicit Instances

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

## Alias Implicits

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

## Implicit Instance Creation

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.
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.

## Syntax

Expand Down
5 changes: 2 additions & 3 deletions docs/docs/reference/contextual-implicit/motivation.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,14 @@ The following pages introduce a redesign of contextual abstractions in Scala. Th

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.

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.
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.

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

- [Context Bounds](./context-bounds.html), which carry over unchanged.
- [Extension Methods](./extension-methods.html) replace implicit classes in a way that integrates better with typeclasses.
- [Implementing Typeclasses](./typeclasses.html) demonstrates how some common typeclasses can be implemented using the new constructs.
- [Typeclass Derivation](./derivation.html) introduces constructs to automatically derive typeclasses for ADTs.
- [Typeclass Derivation](./derivation.html) introduces constructs to automatically derive implicit typeclass instances for ADTs.
- [Multiversal Equality](./multiversal-equality.html) introduces a special typeclass
to support type safe equality.
- [Implicit Function Types](./query-types.html) introduce a way to abstract over implicit parameterization.
Expand All @@ -79,4 +79,3 @@ Could we achieve the same goals by tweaking existing implicits? After having tri
- Third, even if we would somehow succeed with migration, we still have the problem
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
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.

Loading