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