Skip to content

Commit 4cf89cc

Browse files
committed
Adjust and correct the markdown format in extension-methods.md and correct a code example
1 parent 6fac698 commit 4cf89cc

File tree

1 file changed

+40
-21
lines changed

1 file changed

+40
-21
lines changed

docs/docs/reference/contextual/extension-methods.md

Lines changed: 40 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,11 @@ def extension_circumference(c: Circle): Double = c.radius * math.Pi * 2
3030

3131
assert(circle.circumference == extension_circumference(circle))
3232
```
33+
3334
### Operators
3435

3536
The extension method syntax can also be used to define operators. Examples:
37+
3638
```scala
3739
extension (x: String)
3840
def < (y: String): Boolean = ...
@@ -47,11 +49,13 @@ x min 3
4749
```
4850

4951
The three definitions above translate to
52+
5053
```scala
5154
def extension_< (x: String)(y: String): Boolean = ...
5255
def extension_+: (xs: Seq[Elem])(x: Elem): Seq[Elem] = ...
5356
@infix def extension_min(x: Number)(y: Number): Number = ...
5457
```
58+
5559
Note the swap of the two parameters `x` and `xs` when translating
5660
the right-associative operator `+:` to an extension method. This is analogous
5761
to the implementation of right binding operators as normal methods. The Scala
@@ -73,13 +77,15 @@ the two swaps cancel each other out).
7377

7478
If an extension method has type parameters, they come immediately after `extension` and are followed by the extended parameter.
7579
When calling a generic extension method, any explicitly given type arguments follow the method name. So the `second` method could be instantiated as follows.
80+
7681
```scala
7782
List(1, 2, 3).second[Int]
7883
```
79-
Of course, the type argument here would usually be left out since it can be inferred.
8084

85+
Of course, the type argument here would usually be left out since it can be inferred.
8186

8287
Extensions can also take using clauses. For instance, the `+` extension above could equivalently be written with a using clause:
88+
8389
```scala
8490
extension [T](x: T)(using n: Numeric[T])
8591
def - (y: T): T = n.minus(x, y)
@@ -94,6 +100,7 @@ Sometimes, one wants to define several extension methods that share the same
94100
left-hand parameter type. In this case one can "pull out" the common parameters into
95101
a single extension and enclose all methods in braces or an indented region following a '`:`'.
96102
Example:
103+
97104
```scala
98105
extension (ss: Seq[String])
99106

@@ -109,6 +116,7 @@ assuming the common extended value `ss` as receiver.
109116

110117
Collective extensions like these are a shorthand for individual extensions
111118
where each method is defined separately. For instance, the first extension above expands to
119+
112120
```scala
113121
extension (ss: Seq[String])
114122
def longestStrings: Seq[String] =
@@ -118,7 +126,9 @@ extension (ss: Seq[String])
118126
extension (ss: Seq[String])
119127
def longestString: String = ss.longestStrings.head
120128
```
129+
121130
Collective extensions also can take type parameters and have using clauses. Example
131+
122132
```scala
123133
extension [T](xs: List[T])(using Ordering[T])
124134
def smallest(n: Int): List[T] = xs.sorted.take(n)
@@ -167,14 +177,17 @@ trait SafeDiv:
167177
case (Some(d), Some(r)) => Some((d, r))
168178
case _ => None
169179
```
180+
170181
By the second rule, an extension method can be made available by defining a given instance containing it, like this:
182+
171183
```scala
172184
given ops1 as IntOps // brings safeMod into scope
173185

174186
1.safeMod(2)
175187
```
176188

177189
By the third and fourth rule, an extension method is available if it is in the implicit scope of the receiver type or in a given instance in that scope. Example:
190+
178191
```scala
179192
class List[T]:
180193
...
@@ -204,53 +217,58 @@ Assume a selection `e.m[Ts]` where `m` is not a member of `e`, where the type ar
204217
2. If the first rewriting does not typecheck with expected type `T`,
205218
and there is an extension method `m` in some eligible object `o`, the selection is rewritten to `o.extension_m[Ts](e)`. An object `o` is _eligible_ if
206219

207-
- `o` forms part of the implicit scope of `T`, or
208-
- `o` is a given instance that is visible at the point of the application, or
209-
- `o` is a given instance in the implicit scope of `T`.
220+
- `o` forms part of the implicit scope of `T`, or
221+
- `o` is a given instance that is visible at the point of the application, or
222+
- `o` is a given instance in the implicit scope of `T`.
210223

211224
This second rewriting is attempted at the time where the compiler also tries an implicit conversion
212225
from `T` to a type containing `m`. If there is more than one way of rewriting, an ambiguity error results.
213226

214227
An extension method can also be used as an identifier by itself. If an identifier `m` does not
215228
resolve, the identifier is rewritten to:
216229

217-
- `x.m` if the identifier appears in an extension with parameter `x`
218-
- `this.m` otherwise
230+
- `x.m` if the identifier appears in an extension with parameter `x`
231+
- `this.m` otherwise
219232

220233
and the rewritten term is again tried as an application of an extension method. Example:
234+
221235
```scala
222-
extension (s: String)
223-
def position(ch: Char, n: Int): Int =
224-
if n < s.length && s(n) != ch then position(ch, n + 1)
225-
else n
236+
extension (s: String)
237+
def position(ch: Char, n: Int): Int =
238+
if n < s.length && s(n) != ch then position(ch, n + 1)
239+
else n
226240
```
241+
227242
The recursive call `position(ch, n + 1)` expands to `s.position(ch, n + 1)` in this case. The whole extension method rewrites to
243+
228244
```scala
229245
def extension_position(s: String)(ch: Char, n: Int): Int =
230246
if n < s.length && s(n) != ch then extension_position(s)(ch, n + 1)
231247
else n
232248
```
249+
233250
### More Details
234251

235252
1. To avoid confusion, names of normal methods are not allowed to start with `extension_`.
236253

237-
2. A named import such as `import a.m` of an extension method in `a` will make `m`
238-
only available as an extension method. To access it under
239-
`extension_m` that name as to be imported separately. Example:
240-
```scala
241-
object DoubleOps:
242-
extension (x: Double) def ** (exponent: Int): Double =
243-
require(exponent > 0)
244-
if exponent == 0 then 1 else x * (x ** (exponent - 1))
254+
2. A named import such as `import a.m` of an extension method in `a` will make `m` only available as an extension method.
255+
To access it under `extension_m` that name as to be imported separately. Example:
245256

246-
import DoubleOps.{**, extension_**}
247-
assert(2.0 ** 3 == extension_**(2.0)(3))
248-
```
257+
```scala
258+
object DoubleOps:
259+
extension (x: Double) def ** (exponent: Int): Double =
260+
require(exponent >= 0)
261+
if exponent == 0 then 1 else x * (x ** (exponent - 1))
262+
263+
import DoubleOps.{**, extension_**}
264+
assert(2.0 ** 3 == extension_**(2.0)(3))
265+
```
249266

250267
### Syntax
251268

252269
Here are the syntax changes for extension methods and collective extensions relative
253270
to the [current syntax](../../internals/syntax.md).
271+
254272
```
255273
BlockStat ::= ... | Extension
256274
TemplateStat ::= ... | Extension
@@ -260,6 +278,7 @@ Extension ::= ‘extension’ [DefTypeParamClause] ‘(’ DefParam ‘
260278
ExtMethods ::= ExtMethod | [nl] ‘{’ ExtMethod {semi ExtMethod ‘}’
261279
ExtMethod ::= {Annotation [nl]} {Modifier} ‘def’ DefDef
262280
```
281+
263282
`extension` is a soft keyword. It is recognized as a keyword only if it appears
264283
at the start of a statement and is followed by `[` or `(`. In all other cases
265284
it is treated as an identifier.

0 commit comments

Comments
 (0)