@@ -168,38 +168,65 @@ that problem, it is recommended that the name of an extension method is
168
168
preceded by a space and is also followed by a space if there are more parameters
169
169
to come.
170
170
171
- ### Extension Methods and TypeClasses
171
+ ### Extension Methods and Type Classes
172
172
173
- The rules for expanding extension methods make sure that they work seamlessly with typeclasses . For instance, consider ` SemiGroup ` and ` Monoid ` .
173
+ The rules for expanding extension methods make sure that they work seamlessly with type classes . For instance, consider ` SemiGroup ` and ` Monoid ` .
174
174
``` scala
175
- // Two typeclasses :
175
+ // Two type classes :
176
176
trait SemiGroup [T ] {
177
177
def (x : T ) combine(y : T ): T
178
178
}
179
179
trait Monoid [T ] extends SemiGroup [T ] {
180
180
def unit : T
181
181
}
182
-
183
- // An instance declaration:
184
- implicit object StringMonoid extends Monoid [String ] {
185
- def (x : String ) combine (y : String ): String = x.concat(y)
186
- def unit : String = " "
182
+ object Monoid {
183
+ // An instance declaration:
184
+ implicit object StringMonoid extends Monoid [String ] {
185
+ def (x : String ) combine (y : String ): String = x.concat(y)
186
+ def unit : String = " "
187
+ }
187
188
}
188
189
189
190
// Abstracting over a typeclass with a context bound:
190
191
def sum [T : Monoid ](xs : List [T ]): T =
191
192
xs.foldLeft(implicitly[Monoid [T ]].unit)(_.combine(_))
192
193
```
194
+
193
195
In the last line, the call to ` _.combine(_) ` expands to ` (x1, x2) => x1.combine(x2) ` ,
194
196
which expands in turn to ` (x1, x2) => ev.combine(x1, x2) ` where ` ev ` is the implicit
195
197
evidence parameter summoned by the context bound ` [T: Monoid] ` . This works since
196
198
extension methods apply everywhere their enclosing object is available as an implicit.
197
199
200
+ To avoid having to write ` implicitly[Monoid[T]].unit ` to access the ` unit ` method in ` Monoid[T] ` ,
201
+ we can make ` unit ` itself an extension method on the ` Monoid ` _ companion object_ ,
202
+ as shown below:
203
+
204
+ ``` scala
205
+ trait Monoid [T ] extends SemiGroup [T ] {
206
+ def (self : Monoid .type ) unit : T
207
+ }
208
+ object Monoid {
209
+ implicit object StringMonoid extends Monoid [String ] {
210
+ def (x : String ) combine (y : String ): String = x.concat(y)
211
+ def (self : Monoid .type ) unit : String = " "
212
+ }
213
+ }
214
+ ```
215
+
216
+ This allows us to write ` Monoid.unit ` instead of ` implicitly[Monoid[T]].unit ` ,
217
+ letting the expected type distinguish which instance we want to use:
218
+
219
+ ``` scala
220
+ def sum [T : Monoid ](xs : List [T ]): T =
221
+ xs.foldLeft(Monoid .unit)(_.combine(_))
222
+ ```
223
+
224
+
198
225
### Generic Extension Classes
199
226
200
227
As another example, consider implementations of an ` Ord ` type class with a ` minimum ` value:
201
228
``` scala
202
- trait Ord [T ]
229
+ trait Ord [T ] {
203
230
def (x : T ) compareTo (y : T ): Int
204
231
def (x : T ) < (y : T ) = x.compareTo(y) < 0
205
232
def (x : T ) > (y : T ) = x.compareTo(y) > 0
@@ -213,7 +240,7 @@ As another example, consider implementations of an `Ord` type class with a `mini
213
240
}
214
241
215
242
class ListOrd [T : Ord ] extends Ord [List [T ]] {
216
- def (xs : List [T ]) compareTo (ys : List [T ]): Int = (xs, ys) match
243
+ def (xs : List [T ]) compareTo (ys : List [T ]): Int = (xs, ys) match {
217
244
case (Nil , Nil ) => 0
218
245
case (Nil , _) => - 1
219
246
case (_, Nil ) => + 1
0 commit comments