You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
In the main [derivation](./derivation.md) documentation page, we explained the
8
-
details behind `Mirror`s and type class derivation. Here we demonstrate how to
9
-
implement a type class `derived` method using macros only. We follow the same
10
-
example of deriving `Eq` instances and for simplicity we support a `Product`
11
-
type e.g., a case class `Person`. The low-level method we will use to implement
12
-
the `derived` method exploits quotes, splices of both expressions and types and
13
-
the `scala.quoted.Expr.summon` method which is the equivalent of
14
-
`summonFrom`. The former is suitable for use in a quote context, used within
15
-
macros.
7
+
In the main [derivation](./derivation.md) documentation page, we explained the details behind `Mirror`s and type class derivation.
8
+
Here we demonstrate how to implement a type class `derived` method using macros only.
9
+
We follow the same example of deriving `Eq` instances and for simplicity we support a `Product` type e.g., a case class `Person`.
10
+
The low-level technique that we will use to implement the `derived` method exploits quotes, splices of both expressions and types and the `scala.quoted.Expr.summon` method which is the equivalent of `scala.compiletime.summonFrom`.
11
+
The former is suitable for use in a quote context, used within macros.
16
12
17
13
As in the original code, the type class definition is the same:
18
14
@@ -21,185 +17,182 @@ trait Eq[T]:
21
17
defeqv(x: T, y: T):Boolean
22
18
```
23
19
24
-
we need to implement a method `Eq.derived` on the companion object of `Eq` that
25
-
produces a quoted instance for `Eq[T]`. Here is a possible signature,
20
+
We need to implement an inline method `Eq.derived` on the companion object of `Eq` that calls into a macro to produce a quoted instance for `Eq[T]`.
Note, that since a type is used in a subsequent macro compilation stage it will need to be lifted to a `quoted.Type` by using the corresponding context bound (seen in `derivedMacro`).
31
+
32
+
33
+
For comparison, here is the signature of the inline `derived` method from the [main derivation page](./derivation.md):
Note that the macro-based `derived` signature does not have a `Mirror` parameter.
39
+
This is because we can summon the `Mirror` inside the body of `derivedMacro` thus we can omit it from the signature.
40
+
41
+
One additional difference with the body of `derivedMacro` here as opposed to the one with `inline` is that with macros it is simpler to create a fully optimised method body for `eqv`.
42
+
43
+
Let's say we wanted to derive an `Eq` instance for the following case class `Person`,
27
44
```scala
28
-
givenderived[T:Type](usingQuotes):Expr[Eq[T]]
45
+
caseclassPerson(name: String, age: Int) derivesEq
29
46
```
30
47
31
-
and for comparison reasons we give the same signature we had with `inline`:
48
+
the equality check we want to generate is the following:
Note, that in the `inline` case we can merely write
68
-
`summonAll[m.MirroredElemTypes]` inside the inline method but here, since
69
-
`Expr.summon` is required, we can extract the element types in a macro fashion.
70
-
Being inside a macro, our first reaction would be to write the code below. Since
71
-
the path inside the type argument is not stable this cannot be used:
83
+
Note, that in the version without macros, we can merely write `summonInstances[T, m.MirroredElemTypes]` inside the inline method but here, since `Expr.summon` is required, we can extract the element types in a macro fashion.
84
+
Being inside a macro, our first reaction would be to write the code below:
72
85
73
86
```scala
74
87
'{
75
-
summonAll[$m.MirroredElemTypes]
88
+
summonInstances[T, $m.MirroredElemTypes]
76
89
}
77
90
```
78
91
79
-
Instead we extract the tuple-type for element types using pattern matching over
80
-
quotes and more specifically of the refined type:
92
+
However, since the path inside the type argument is not stable this cannot be used.
93
+
Instead we extract the tuple-type for element types using pattern matching over quotes and more specifically of the refined type:
Following the rules in [Macros](../metaprogramming/metaprogramming.md) we create two methods.
114
-
One that hosts the top-level splice `eqv` and one that is the implementation.
115
-
Alternatively and what is shown below is that we can call the `eqv` method
116
-
directly. The `eqGen` can trigger the derivation.
102
+
To understand `deriveOrSummon`, consider that if `elem` derives from the parent `T` type, then it is a recursive derivation.
103
+
Recursive derivation usually happens for types such as `scala.collection.immutable.::`. If `elem` does not derive from `T`, then there must exist a contextual `Eq[elem]` instance.
0 commit comments