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
When is an extension method applicable? There are two possibilities.
35
+
When is an extension method applicable? There are two possibilities:
36
36
37
-
- An extension method is applicable if it is visible under a simple name, by being defined
37
+
1. An extension method is applicable if it is visible under a simple name, by being defined
38
38
or inherited or imported in a scope enclosing the application.
39
-
- An extension method is applicable if it is a member of some given instance at the point of the application.
39
+
2. An extension method is applicable if it is a member of some given instance at the point of the application.
40
40
41
-
As an example, consider an extension method `longestStrings` on `Seq[String]` defined in a trait `StringSeqOps`.
41
+
Here is an example for the first rule:
42
42
43
43
```scala
44
-
traitStringSeqOps {
45
-
def (xs: Seq[String]).longestStrings = {
46
-
valmaxLength= xs.map(_.length).max
47
-
xs.filter(_.length == maxLength)
48
-
}
44
+
traitIntOps {
45
+
def (i: Int).isZero:Boolean= i ==0
46
+
47
+
def (i: Int).safeMod(x: Int):Option[Int] =
48
+
// extension method defined in same scope IntOps
49
+
if x.isZero thenNone
50
+
elseSome(i % x)
51
+
}
52
+
53
+
objectIntOpsExextendsIntOps {
54
+
def (i: Int).safeDiv(x: Int):Option[Int] =
55
+
// extension method brought into scope via inheritance from IntOps
56
+
if x.isZero thenNone
57
+
elseSome(i % x)
58
+
}
59
+
60
+
traitSafeDiv {
61
+
importIntOpsEx._// brings safeDiv and safeMod into scope
62
+
63
+
def (i: Int) divide(d: Int) :Option[(Int, Int)] =
64
+
// extension methods imported and thus in scope
65
+
(i.safeDiv(d), i.safeMod(d)) match {
66
+
case (Some(d), Some(r)) =>Some((d, r))
67
+
case _ =>None
68
+
}
49
69
}
50
70
```
51
-
We can make the extension method available by defining a given `StringSeqOps` instance, like this:
52
-
```scala
53
-
givenops1 as StringSeqOps
54
-
```
55
-
Then
71
+
72
+
We build up on the above example to outline the second point.
73
+
We can make an extension method available by defining a given instance containing it, like this:
56
74
```scala
57
-
List("here", "is", "a", "list").longestStrings
75
+
givenops1 as IntOps// brings safeMod into scope
76
+
77
+
1.safeMod(2)
58
78
```
59
-
is legal everywhere `ops1` is available. 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.
60
79
80
+
Then `safeMod` is legal everywhere `ops1` is available. Anonymous givens (and any other form of givens) are supported as well:
61
81
```scala
62
-
objectops2extendsStringSeqOps
63
-
importops2.longestStrings
64
-
List("here", "is", "a", "list").longestStrings
82
+
givenSafeDiv//brings divide into scope (safeMod and safeDiv are not automatically exported)
83
+
84
+
1.divide(2)
65
85
```
86
+
66
87
The precise rules for resolving a selection to an extension method are as follows.
67
88
68
89
Assume a selection `e.m[Ts]` where `m` is not a member of `e`, where the type arguments `[Ts]` are optional,
@@ -94,20 +115,28 @@ x min 3
94
115
```
95
116
For alphanumeric extension operators like `min` an `@infix` annotation is implied.
96
117
118
+
<!--
119
+
TODO: what about @alpha for the non alphanumeric operators, should be required according to
"Symbolic methods without @alpha annotations are deprecated"
122
+
-->
123
+
97
124
The three definitions above translate to
98
125
```scala
99
126
def< (x: String)(y: String) = ...
100
127
def+: (xs: Seq[Elem])(x: Elem) = ...
101
128
defmin(x: Number)(y: Number) = ...
102
129
```
103
130
Note the swap of the two parameters `x` and `xs` when translating
104
-
the right-binding operator `+:` to an extension method. This is analogous
131
+
the right-associative operator `+:` to an extension method. This is analogous
105
132
to the implementation of right binding operators as normal methods.
106
133
107
134
108
135
### Generic Extensions
109
136
110
-
The `StringSeqOps` examples extended a specific instance of a generic type. It is also possible to extend a generic type by adding type parameters to an extension method. Examples:
137
+
The `IntOps` examples extended a non generic type.
138
+
It is also possible to extend a specific instance of a generic type (e.g. Seq[String] -- see `stringOps` further below).
139
+
Moreover, it is also possible to extend generic types by adding type parameters to an extension method. Examples:
If an extension method has type parameters, they come immediately after the `def` and are followed by the extended parameter. When calling a generic extension method, any explicitly given type arguments follow the method name. So the `second` method can be instantiated as follows:
152
+
If an extension method has type parameters, they come immediately after the `def` and are followed by the extended parameter.
153
+
When calling a generic extension method, any explicitly given type arguments follow the method name. So the `second` method can be instantiated as follows:
124
154
```scala
125
155
List(1, 2, 3).second[Int]
126
156
```
157
+
(it's only a showcase, the compiler could of course infer the type).
0 commit comments