diff --git a/docs/docs/reference/contextual-instance/derivation.md b/docs/docs/reference/contextual-instance/derivation.md index 33a7516ad8a3..72c12b951bb1 100644 --- a/docs/docs/reference/contextual-instance/derivation.md +++ b/docs/docs/reference/contextual-instance/derivation.md @@ -10,11 +10,11 @@ enum Tree[T] derives Eql, Ordering, Pickling { case Leaf(elem: T) } ``` -The `derives` clause generates evidence for the `Eql`, `Ordering`, and `Pickling` traits in the companion object `Tree`: +The `derives` clause generates implicit instances of the `Eql`, `Ordering`, and `Pickling` traits in the companion object `Tree`: ```scala -evidence [T: Eql] for Eql[Tree[T]] = Eql.derived -evidence [T: Ordering] for Ordering[Tree[T]] = Ordering.derived -evidence [T: Pickling] for Pickling[Tree[T]] = Pickling.derived +instance [T: Eql] of Eql[Tree[T]] = Eql.derived +instance [T: Ordering] of Ordering[Tree[T]] = Ordering.derived +instance [T: Pickling] of Pickling[Tree[T]] = Pickling.derived ``` ### Deriving Types @@ -42,7 +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 inferable parameter of type `Generic` that determines the _shape_ of the deriving type `T` and it computes the typeclass implementation according to that shape. Evidence for `Generic` is generated automatically for any type that derives a typeclass with a `derived` +That is, the `derived` method takes an inferable 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 instance of `Generic` 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 @@ -94,9 +94,9 @@ 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` evidence 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 of `Generic[C[T_1,...,T_n]]` that follows the outline below: ```scala -evidence [T_1, ..., T_n] for Generic[C[T_1,...,T_n]] { +instance [T_1, ..., T_n] of Generic[C[T_1,...,T_n]] { type Shape = ... ... } @@ -114,7 +114,7 @@ would produce: object Result { import scala.compiletime.Shape._ - evidence [T, E] for Generic[Result[T, E]] { + instance [T, E] of Generic[Result[T, E]] { type Shape = Cases[( Case[Ok[T], T *: Unit], Case[Err[E], E *: Unit] @@ -214,8 +214,8 @@ trait Eql[T] { def eql(x: T, y: T): Boolean } ``` -We need to implement a method `Eql.derived` that produces an instance of `Eql[T]` provided -there exists evidence of type `Generic[T]`. Here's a possible solution: +We need to implement a method `Eql.derived` that produces an implicit instance of `Eql[T]` provided +there exists an implicit instance of `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 = { @@ -234,7 +234,7 @@ there exists evidence of type `Generic[T]`. Here's a possible solution: The implementation of the inline method `derived` creates an instance of `Eql[T]` and implements its `eql` method. The right-hand side of `eql` mixes compile-time and runtime elements. In the code above, runtime elements are marked with a number in parentheses, i.e `(1)`, `(2)`, `(3)`. Compile-time calls that expand to runtime code are marked with a number in brackets, i.e. `[4]`, `[5]`. The implementation of `eql` consists of the following steps. - 1. Map the compared values `x` and `y` to their mirrors using the `reflect` method of the implicitly passed `Generic` evidence `(1)`, `(2)`. + 1. Map the compared values `x` and `y` to their mirrors using the `reflect` method of the implicitly passed `Generic` instance `(1)`, `(2)`. 2. Match at compile-time against the shape of the ADT given in `ev.Shape`. Dotty does not have a construct for matching types directly, but we can emulate it using an `inline` match over an `erasedValue`. Depending on the actual type `ev.Shape`, the match will reduce at compile time to one of its two alternatives. 3. If `ev.Shape` is of the form `Cases[alts]` for some tuple `alts` of alternative types, the equality test consists of comparing the ordinal values of the two mirrors `(3)` and, if they are equal, comparing the elements of the case indicated by that ordinal value. That second step is performed by code that results from the compile-time expansion of the `eqlCases` call `[4]`. 4. If `ev.Shape` is of the form `Case[elems]` for some tuple `elems` for element types, the elements of the case are compared by code that results from the compile-time expansion of the `eqlElems` call `[5]`. @@ -298,14 +298,14 @@ non-empty, say of form `elem *: elems1`, the following code is produced: The last, and in a sense most interesting part of the derivation is the comparison of a pair of element values in `tryEql`. Here is the definition of this method: ```scala - inline def tryEql[T](x: T, y: T) = implicit match { + inline def tryEql[T](x: T, y: T) = instance match { case ev: Eql[T] => ev.eql(x, y) // (15) case _ => error("No `Eql` instance was found for $T") } ``` -`tryEql` is an inline method that takes an element type `T` and two element values of that type as arguments. It is defined using an `evidence match` that tries to find evidence for `Eql[T]`. If an instance `ev` is found, it proceeds by comparing the arguments using `ev.eql`. On the other hand, if no instance is found +`tryEql` is an inline method that takes an element type `T` and two element values of that type as arguments. It is defined using an `instance match` that tries to find an implicit instance of `Eql[T]`. If an instance `ev` is found, it proceeds by comparing the arguments using `ev.eql`. On the other hand, if no instance is found this signals a compilation error: the user tried a generic derivation of `Eql` for a class with an element type that does not support an `Eql` instance itself. The error is signaled by calling the `error` method defined in `scala.compiletime`. @@ -314,7 +314,7 @@ calling the `error` method defined in `scala.compiletime`. **Example:** Here is a slightly polished and compacted version of the code that's generated by inline expansion for the derived `Eql` instance of class `Tree`. ```scala -evidence [T] given (elemEq: Eql[T]) for Eql[Tree[T]] { +instance [T] given (elemEq: Eql[T]) of Eql[Tree[T]] { def eql(x: Tree[T], y: Tree[T]): Boolean = { val ev = the[Generic[Tree[T]]] val mx = ev.reflect(x) @@ -333,21 +333,22 @@ evidence [T] given (elemEq: Eql[T]) for Eql[Tree[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 evidence 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 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: ```scala -evidence [T: Ordering]: Ordering[Option[T]] = Ordering.derived +instance [T: Ordering] of Ordering[Option[T]] = Ordering.derived ``` Usually, the `Ordering.derived` clause has an inferable parameter of type `Generic[Option[T]]`. Since the `Option` trait has a `derives` clause, -the necessary evidence is already present in the companion object of `Option`. -If the ADT in question does not have a `derives` clause, evidence 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 of `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 evidence is found, the compiler will synthesize it. +This is similar to the situation with type tags or class tags: If no instance is found, +the compiler will synthesize one. ### Syntax diff --git a/docs/docs/reference/contextual-instance/extension-methods.md b/docs/docs/reference/contextual-instance/extension-methods.md index 779b0b2a47ea..29a0420501c5 100644 --- a/docs/docs/reference/contextual-instance/extension-methods.md +++ b/docs/docs/reference/contextual-instance/extension-methods.md @@ -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 evidence 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`. @@ -48,7 +48,7 @@ trait StringSeqOps { } } ``` -We can make the extension method available by defining evidence for `StringSeqOps`, like this: +We can make the extension method available by defining an implicit instance of `StringSeqOps`, like this: ```scala instance ops1 of StringSeqOps ``` @@ -56,7 +56,7 @@ Then ```scala List("here", "is", "a", "list").longestStrings ``` -is legal everywhere `ops1` is available as evidence. Alternatively, we can define `longestStrings` as a member of a normal object. But then the method has to be brought into scope to be usable as an extension method. +is legal everywhere `ops1` is available as an implicit. Alternatively, we can define `longestStrings` as a member of a normal object. But then the method has to be brought into scope to be usable as an extension method. ```scala object ops2 extends StringSeqOps @@ -69,32 +69,32 @@ Assume a selection `e.m[Ts]` where `m` is not a member of `e`, where the type ar and where `T` is the expected type. The following two rewritings are tried in order: 1. The selection is rewritten to `m[Ts](e)`. - 2. If the first rewriting does not typecheck with expected type `T`, and there is evidence `i` - in either the current scope or in the evidence scope of `T`, and `i` defines an extension + 2. If the first rewriting does not typecheck with expected type `T`, and there is an implicit `i` + in either the current scope or in the implicit scope of `T`, and `i` defines an extension method named `m`, then selection is expanded to `i.m[Ts](e)`. This second rewriting is attempted at the time where the compiler also tries an implicit conversion 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 evidence 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`). -### Evidence for Extension Methods +### Implicit Instances for Extension Methods -Evidence that defines extension methods can also be defined without a `for` clause. E.g., +Implicits that wrap extension methods can also be defined without an `of` clause. E.g., ```scala -evidence StringOps { +instance StringOps { def (xs: Seq[String]) longestStrings: Seq[String] = { val maxLength = xs.map(_.length).max xs.filter(_.length == maxLength) } } -evidence { +instance { def (xs: List[T]) second[T] = xs.tail.head } ``` -If such an evidence is anonymous (as in the second example above), its name is synthesized from the name +If such an instance is anonymous (as in the second example above), its name is synthesized from the name of the first defined extension method. ### Operators diff --git a/docs/docs/reference/contextual-instance/inferable-by-name-parameters.md b/docs/docs/reference/contextual-instance/inferable-by-name-parameters.md index 48e8939b62ad..651591d5edf1 100644 --- a/docs/docs/reference/contextual-instance/inferable-by-name-parameters.md +++ b/docs/docs/reference/contextual-instance/inferable-by-name-parameters.md @@ -1,6 +1,6 @@ --- layout: doc-page -title: "Implicit By-Name Parameters" +title: "Inferable By-Name Parameters" --- Inferable by-name parameters can be used to avoid a divergent inferred expansion. Example: @@ -42,7 +42,7 @@ The precise steps for constructing an inferable argument for a by-name parameter 1. This instance is not immediately available as 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 inferred argument to a by-name parameter. - 1. If this search succeeds with expression `E`, and `E` contains references to the evidence `lv`, replace `E` by + 1. If this search succeeds with expression `E`, and `E` contains references to `lv`, replace `E` by ```scala diff --git a/docs/docs/reference/contextual-instance/multiversal-equality.md b/docs/docs/reference/contextual-instance/multiversal-equality.md index cd9523c38a8e..d9f0fce13560 100644 --- a/docs/docs/reference/contextual-instance/multiversal-equality.md +++ b/docs/docs/reference/contextual-instance/multiversal-equality.md @@ -30,7 +30,7 @@ that derives `Eql`, e.g. ```scala class T derives Eql ``` -Alternatively, one can also provide the derived evidence directly, like this: +Alternatively, one can also provide the derived instance directly, like this: ```scala instance of Eql[T, T] = Eql.derived ``` @@ -74,7 +74,7 @@ defined as follows: def eqlAny[L, R]: Eql[L, R] = Eql.derived ``` -Even though `eqlAny` is not declared as `evidence`, the compiler will still +Even though `eqlAny` is not declared as `instance`, the compiler will still construct an `eqlAny` instance as answer to an implicit search for the type `Eql[L, R]`, unless `L` or `R` have `Eql` instances defined on them, or the language feature `strictEquality` is enabled @@ -140,7 +140,7 @@ The `Eql` object defines implicit instances for - `java.lang.Number`, `java.lang.Boolean`, and `java.lang.Character`, - `scala.collection.Seq`, and `scala.collection.Set`. -Instances are defined so that everyone of these types is has a reflexive `Eql` evidence, and the following holds: +Instances are defined so that everyone of these types has a reflexive `Eql` instance, and the following holds: - Primitive numeric types can be compared with each other. - Primitive numeric types can be compared with subtypes of `java.lang.Number` (and _vice versa_). diff --git a/docs/docs/reference/contextual-instance/query-types.md b/docs/docs/reference/contextual-instance/query-types.md index 716a6b9ad10d..27175cb7b11e 100644 --- a/docs/docs/reference/contextual-instance/query-types.md +++ b/docs/docs/reference/contextual-instance/query-types.md @@ -27,7 +27,7 @@ context query literal, `E` is converted to a context query literal by rewriting ``` where the names `x_1`, ..., `x_n` are arbitrary. This expansion is performed before the expression `E` is typechecked, which means that `x_1`, ..., `x_n` -are available as evidence in `E`. +are available as implicits in `E`. Like query types, query literals are written with a `given` prefix. They differ from normal function literals in two ways: @@ -139,9 +139,9 @@ object Test { ``` **Explanations**: We use a context query type `given WrappedResult[T] => Boolean` as the type of the condition of `ensuring`. An argument to `ensuring` such as -`(result == 6)` will therefore have evidence of type `WrappedResult[T]` in +`(result == 6)` will therefore have an implicit instance of type `WrappedResult[T]` in scope to pass along to the `result` method. `WrappedResult` is a fresh type, to make sure -that we do not get unwanted evidence types in scope (this is good practice in all cases +that we do not get unwanted implicit instances in scope (this is good practice in all cases where given clauses are involved). Since `WrappedResult` is an opaque type alias, its values need not be boxed, and since `ensuring` is added as an extension method, its argument does not need boxing either. Hence, the implementation of `ensuring` is as about as efficient