Skip to content

Commit ab3de89

Browse files
committed
Syntax change: "extension on" instead of "extension of"
"extension on" is more precise. The thing after the "of/on" is a parameter. The definition is not an extension "of" this parameter (what does that even mean?), but rather an extension of the parameter's underlying type. Note that Dart also uses "extension on".
1 parent 6c380b2 commit ab3de89

27 files changed

+54
-53
lines changed

compiler/src/dotty/tools/dotc/core/StdNames.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -529,8 +529,8 @@ object StdNames {
529529
val notify_ : N = "notify"
530530
val null_ : N = "null"
531531
val nullExpr: N = "nullExpr"
532-
val of: N = "of"
533532
val ofDim: N = "ofDim"
533+
val on: N = "on"
534534
val opaque: N = "opaque"
535535
val open: N = "open"
536536
val ordinal: N = "ordinal"

compiler/src/dotty/tools/dotc/parsing/Parsers.scala

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -948,9 +948,9 @@ object Parsers {
948948
def followingIsExtension() =
949949
val lookahead = in.LookaheadScanner()
950950
lookahead.nextToken()
951-
if lookahead.isIdent && !lookahead.isIdent(nme.of) then
951+
if lookahead.isIdent && !lookahead.isIdent(nme.on) then
952952
lookahead.nextToken()
953-
lookahead.isIdent(nme.of)
953+
lookahead.isIdent(nme.on)
954954

955955
/* --------- OPERAND/OPERATOR STACK --------------------------------------- */
956956

@@ -3538,9 +3538,9 @@ object Parsers {
35383538
*/
35393539
def extensionDef(start: Offset, mods: Modifiers): ModuleDef =
35403540
in.nextToken()
3541-
val name = if isIdent && !isIdent(nme.of) then ident() else EmptyTermName
3542-
if !isIdent(nme.of) then syntaxErrorOrIncomplete("`of` expected")
3543-
if isIdent(nme.of) then in.nextToken()
3541+
val name = if isIdent && !isIdent(nme.on) then ident() else EmptyTermName
3542+
if !isIdent(nme.on) then syntaxErrorOrIncomplete("`on` expected")
3543+
if isIdent(nme.on) then in.nextToken()
35443544
val tparams = typeParamClauseOpt(ParamOwner.Def)
35453545
val extParams = paramClause(0, prefix = true)
35463546
val givenParamss = paramClauses(givenOnly = true)

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

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -128,19 +128,19 @@ A collective extension defines one or more concrete methods that have the same t
128128
and prefix parameter. Examples:
129129

130130
```scala
131-
extension stringOps of (xs: Seq[String]) {
131+
extension stringOps on (xs: Seq[String]) {
132132
def longestStrings: Seq[String] = {
133133
val maxLength = xs.map(_.length).max
134134
xs.filter(_.length == maxLength)
135135
}
136136
}
137137

138-
extension listOps of [T](xs: List[T]) {
138+
extension listOps on [T](xs: List[T]) {
139139
def second = xs.tail.head
140140
def third: T = xs.tail.tail.head
141141
}
142142

143-
extension of [T](xs: List[T])(given Ordering[T]) {
143+
extension on [T](xs: List[T])(given Ordering[T]) {
144144
def largest(n: Int) = xs.sorted.takeRight(n)
145145
}
146146
```
@@ -164,18 +164,19 @@ given extension_largest_List_T: AnyRef {
164164
}
165165
```
166166

167-
`extension` and `of` are soft keywords. They can also be used as a regular identifiers.
167+
`extension` and `on` are soft keywords. They can also be used as a regular identifiers.
168168

169169
### Syntax
170170

171171
Here are the syntax changes for extension methods and given extensions relative
172-
to the [current syntax](../../internals/syntax.md). `extension` is a soft keyword, recognized only after a `given`. It can be used as an identifier everywhere else.
172+
to the [current syntax](../../internals/syntax.md). `extension` is a soft keyword, recognized only in tandem with `on`. It can be used as an identifier everywhere else.
173+
173174
```
174175
DefSig ::= ...
175176
| ExtParamClause [nl] [‘.’] id DefParamClauses
176177
ExtParamClause ::= [DefTypeParamClause] ‘(’ DefParam ‘)’
177178
TmplDef ::= ...
178179
| ‘extension’ ExtensionDef
179-
ExtensionDef ::= [id] ‘of’ ExtParamClause {GivenParamClause} ExtMethods
180+
ExtensionDef ::= [id] ‘on’ ExtParamClause {GivenParamClause} ExtMethods
180181
ExtMethods ::= ‘{’ ‘def’ DefDef {semi ‘def’ DefDef} ‘}’
181182
```

docs/docs/reference/contextual/relationship-implicits.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ Anonymous collective extensions also get compiler synthesized names, which are f
7272

7373
For example, the extension
7474
```scala
75-
extension of [T] (xs: List[T]) {
75+
extension on [T] (xs: List[T]) {
7676
def second = ...
7777
}
7878
```

tests/neg/extension-methods.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ object Test {
1010
"".l2 // error
1111
1.l1 // error
1212

13-
extension of [T](xs: List[T]) {
13+
extension on [T](xs: List[T]) {
1414
def (x: Int).f1: T = ??? // error: No extension method allowed here, since collective parameters are given
1515
def f2[T]: T = ??? // error: T is already defined as type T
1616
def f3(xs: List[T]) = ??? // error: xs is already defined as value xs

tests/neg/extmethod-overload.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
object Test {
2-
extension a of (x: Int) {
2+
extension a on (x: Int) {
33
def |+| (y: Int) = x + y
44
}
55

6-
extension b of (x: Int) {
6+
extension b on (x: Int) {
77
def |+| (y: String) = x + y.length
88
}
99
assert((1 |+| 2) == 3) // error ambiguous

tests/neg/i5455.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ object Library {
1111
def toInt(n: Nat): Int = n
1212

1313
}
14-
extension of (x: Nat) {
14+
extension on (x: Nat) {
1515
def * (y: Nat): Nat = x * y
1616
def toInt: Int = x
1717
}

tests/neg/i6801.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
extension myNumericOps of [T](x: T) {
1+
extension myNumericOps on [T](x: T) {
22
def + (y: T)(given n: Numeric[T]): T = n.plus(x,y)
33
}
44
def foo[T: Numeric](x: T) = 1f + x // error: no implicit argument of type Numeric[Any]

tests/neg/i6900.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
object Test2 {
22

33
// Works with extension method
4-
extension of [A](a: A) with
4+
extension on [A](a: A) with
55
def foo[C]: C => A = _ => a // error: extension method cannot have type parameters
66

77
1.foo.foo

tests/neg/i7529.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
extension fooOps of [A](a: A) with
1+
extension fooOps on [A](a: A) with
22

33
@nonsense // error: not found: nonsense
44
def foo = ???

0 commit comments

Comments
 (0)