Skip to content

Commit cb3af3f

Browse files
committed
Document new changes
The new syntax allows arbitrary interleaving of type and term clauses for methods TypelessClause{|s} is added for class constructors since they still don't allow interleaving of type parameters Also unifies the affected grammar variable names so that <x>s means "one or more <x>" Implicit clauses are moved apart from term clause to make it more obvious they can only be the last clause
1 parent 5071386 commit cb3af3f

File tree

4 files changed

+144
-30
lines changed

4 files changed

+144
-30
lines changed

docs/_docs/internals/syntax.md

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -343,9 +343,6 @@ ClsTypeParamClause::= ‘[’ ClsTypeParam {‘,’ ClsTypeParam} ‘]’
343343
ClsTypeParam ::= {Annotation} [‘+’ | ‘-’] TypeDef(Modifiers, name, tparams, bounds)
344344
id [HkTypeParamClause] TypeParamBounds Bound(below, above, context)
345345
346-
DefTypeParamClause::= ‘[’ DefTypeParam {‘,’ DefTypeParam} ‘]’
347-
DefTypeParam ::= {Annotation} id [HkTypeParamClause] TypeParamBounds
348-
349346
TypTypeParamClause::= ‘[’ TypTypeParam {‘,’ TypTypeParam} ‘]’
350347
TypTypeParam ::= {Annotation} id [HkTypeParamClause] TypeBounds
351348
@@ -359,13 +356,24 @@ ClsParamClause ::= [nl] ‘(’ ClsParams ‘)’
359356
ClsParams ::= ClsParam {‘,’ ClsParam}
360357
ClsParam ::= {Annotation} ValDef(mods, id, tpe, expr) -- point of mods on val/var
361358
[{Modifier} (‘val’ | ‘var’) | ‘inline’] Param
362-
Param ::= id ‘:’ ParamType [‘=’ Expr]
363359
364-
DefParamClauses ::= {DefParamClause} [[nl] ‘(’ [‘implicit’] DefParams ‘)’]
365-
DefParamClause ::= [nl] ‘(’ DefParams ‘)’ | UsingParamClause
366-
UsingParamClause ::= [nl] ‘(’ ‘using’ (DefParams | FunArgTypes) ‘)’
367-
DefParams ::= DefParam {‘,’ DefParam}
368-
DefParam ::= {Annotation} [‘inline’] Param ValDef(mods, id, tpe, expr) -- point of mods at id.
360+
DefParamClauses ::= DefParamClause { DefParamClause }
361+
DefParamClause ::= DefTypeParamClause
362+
| DefTermParamClause
363+
| UsingParamClause
364+
TypelessClauses ::= TypelessClause {TypelessClause}
365+
TypelessClause ::= DefTermParamClause
366+
| UsingParamClause
367+
368+
DefTypeParamClause::= [nl] ‘[’ DefTypeParam {‘,’ DefTypeParam} ‘]’
369+
DefTypeParam ::= {Annotation} id [HkTypeParamClause] TypeParamBounds
370+
DefTermParamClause::= [nl] ‘(’ [DefTermParams] ‘)’
371+
UsingParamClause ::= [nl] ‘(’ ‘using’ (DefTermParams | FunArgTypes) ‘)’
372+
DefImplicitClause ::= [nl] ‘(’ ‘implicit’ DefTermParams ‘)’
373+
374+
DefTermParams ::= DefTermParam {‘,’ DefTermParam}
375+
DefTermParam ::= {Annotation} [‘inline’] Param ValDef(mods, id, tpe, expr) -- point of mods at id.
376+
Param ::= id ‘:’ ParamType [‘=’ Expr]
369377
```
370378

371379
### Bindings and Imports
@@ -416,7 +424,7 @@ Dcl ::= RefineDcl
416424
ValDcl ::= ids ‘:’ Type PatDef(_, ids, tpe, EmptyTree)
417425
VarDcl ::= ids ‘:’ Type PatDef(_, ids, tpe, EmptyTree)
418426
DefDcl ::= DefSig ‘:’ Type DefDef(_, name, tparams, vparamss, tpe, EmptyTree)
419-
DefSig ::= id [DefTypeParamClause] DefParamClauses
427+
DefSig ::= id [DefParamClauses] [DefImplicitClause]
420428
TypeDcl ::= id [TypeParamClause] {FunParamClause} TypeBounds TypeDefTree(_, name, tparams, bound
421429
[‘=’ Type]
422430
@@ -427,8 +435,8 @@ Def ::= ‘val’ PatDef
427435
| TmplDef
428436
PatDef ::= ids [‘:’ Type] ‘=’ Expr
429437
| Pattern2 [‘:’ Type] ‘=’ Expr PatDef(_, pats, tpe?, expr)
430-
DefDef ::= DefSig [‘:’ Type] ‘=’ Expr DefDef(_, name, tparams, vparamss, tpe, expr)
431-
| ‘this’ DefParamClause DefParamClauses ‘=’ ConstrExpr DefDef(_, <init>, Nil, vparamss, EmptyTree, expr | Block)
438+
DefDef ::= DefSig [‘:’ Type] ‘=’ Expr DefDef(_, name, paramss, tpe, expr)
439+
| ‘this’ TypelessClauses [DefImplicitClause] ‘=’ ConstrExpr DefDef(_, <init>, vparamss, EmptyTree, expr | Block)
432440
433441
TmplDef ::= ([‘case’] ‘class’ | ‘trait’) ClassDef
434442
| [‘case’] ‘object’ ObjectDef
@@ -440,10 +448,10 @@ ConstrMods ::= {Annotation} [AccessModifier]
440448
ObjectDef ::= id [Template] ModuleDef(mods, name, template) // no constructor
441449
EnumDef ::= id ClassConstr InheritClauses EnumBody
442450
GivenDef ::= [GivenSig] (AnnotType [‘=’ Expr] | StructuralInstance)
443-
GivenSig ::= [id] [DefTypeParamClause] {UsingParamClause} ‘:’ -- one of `id`, `DefParamClause`, `UsingParamClause` must be present
451+
GivenSig ::= [id] [DefTypeParamClause] {UsingParamClause} ‘:’ -- one of `id`, `DefTypeParamClause`, `UsingParamClause` must be present
444452
StructuralInstance ::= ConstrApp {‘with’ ConstrApp} [‘with’ WithTemplateBody]
445453
Extension ::= ‘extension’ [DefTypeParamClause] {UsingParamClause}
446-
‘(’ DefParam ‘)’ {UsingParamClause} ExtMethods
454+
‘(’ DefTermParam ‘)’ {UsingParamClause} ExtMethods
447455
ExtMethods ::= ExtMethod | [nl] <<< ExtMethod {semi ExtMethod} >>>
448456
ExtMethod ::= {Annotation [nl]} {Modifier} ‘def’ DefDef
449457
| Export

docs/_docs/reference/contextual/using-clauses.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,8 +146,8 @@ Here is the new syntax of parameters and arguments seen as a delta from the [sta
146146

147147
```
148148
ClsParamClause ::= ... | UsingClsParamClause
149-
DefParamClauses ::= ... | UsingParamClause
149+
DefParamClause ::= ... | UsingParamClause
150150
UsingClsParamClause ::= ‘(’ ‘using’ (ClsParams | Types) ‘)’
151-
UsingParamClause ::= ‘(’ ‘using’ (DefParams | Types) ‘)’
151+
UsingParamClause ::= ‘(’ ‘using’ (DefTermParams | Types) ‘)’
152152
ParArgumentExprs ::= ... | ‘(’ ‘using’ ExprsInParens ‘)’
153153
```
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
---
2+
layout: doc-page
3+
title: "Generalized Method Syntax"
4+
movedTo: https://docs.scala-lang.org/scala3/reference/other-new-features/generalized-method-syntax.html
5+
---
6+
7+
The inclusion of using clauses is not the only way in which methods have been updated, type parameter clauses are now allowed in any number and at any position.
8+
9+
## Syntax Changes
10+
11+
### In Scala 2
12+
13+
The old syntax only allowed zero or one type parameter clause, followed by any number of term clauses, optionnally followed by an implicit clause:
14+
15+
```scala
16+
def foo[T, U](x: T)(y: U)(z: Int, s: String)(a: Array[T])(implicit List[U])
17+
```
18+
19+
### In Scala 3
20+
21+
The new syntax allows any number of type, term and using clause, in any order, optionnaly followed by an implicit clause:
22+
(do note however that [implicit clause are discouraged, in favor of using clauses](https://docs.scala-lang.org/scala3/reference/contextual/relationship-implicits.html))
23+
24+
```scala
25+
def foo[T, U](x: T)(y: U)[V](z: V, s: String)[A](a: Array[A])(implicit List[U])
26+
```
27+
28+
### Unchanged
29+
30+
Class definitions and type declarations are unaffected, there can only be up to one type clause, in leading posion.
31+
32+
## Motivation
33+
34+
The new syntax is a powerful but natural extension of the old one, it allows new design patterns while staying intuitive and legible.
35+
36+
### Dependent Type Clauses
37+
38+
As type clauses can come after term clauses, it is now possible to have type parameters depend on term parameters:
39+
40+
```scala
41+
trait Key { type Value }
42+
trait DB {
43+
def get(k: Key): Option[k.Value] // dependent return type
44+
def getOrElse(k: Key)[V >: k.Value](default: V): V // dependent type parameter
45+
}
46+
```
47+
48+
Note that simply replacing `V` by `k.Value` would not be equivalent. For example, if `k.Value` is `Int`, the above allows:
49+
`getOrElse(k)[Number](0.1)`, which returns a `Number`.
50+
51+
### Partial Inference
52+
53+
It is now possible to only infer some of the type parameters, this reduces boilerplate at the use site:
54+
```scala
55+
trait StaticSizeList[S <: Int & Singleton, T]
56+
def filled[S <: Int & Singleton][T](x: T): StaticSizeList[S,T] = ???
57+
val helloes = filled[4]("Hello!") // S=4, and T is inferred
58+
```
59+
60+
## Details
61+
62+
### Application
63+
64+
Method application is unchanged, in cases where multiple type clauses are expected but not all are passed, the rightmost ones are inferred.
65+
66+
In particular, the following does not type check, even though the argument `Char` is only valid for `C`:
67+
```scala
68+
def triple[A <: Int][B <: String][C <: Char](a: A, b: B, c: C) = ???
69+
triple[Int][Char](0,"",'c') // error: Char does not conform to upperbound String
70+
```
71+
72+
### Extension Methods
73+
74+
Naturally extension methods follow the same syntax, so the following is valid:
75+
```scala
76+
extension [T](l1: List[T])
77+
def zipWith[U](l2: List[U])[V](l3: List[V]): List[(T,U,V)]
78+
```
79+
80+
### Formal syntax
81+
82+
```
83+
DefDcl ::= DefSig ‘:’ Type
84+
DefDef ::= DefSig [‘:’ Type] ‘=’ Expr
85+
DefSig ::= id [DefParamClauses] [DefImplicitClause]
86+
DefParamClauses ::= DefParamClause { DefParamClause }
87+
DefParamClause ::= DefTypeParamClause
88+
| DefTermParamClause
89+
| UsingParamClause
90+
DefTypeParamClause::= [nl] ‘[’ DefTypeParam {‘,’ DefTypeParam} ‘]’
91+
DefTypeParam ::= {Annotation} id [HkTypeParamClause] TypeParamBounds
92+
DefTermParamClause::= [nl] ‘(’ [DefTermParams] ‘)’
93+
UsingParamClause ::= [nl] ‘(’ ‘using’ (DefTermParams | FunArgTypes) ‘)’
94+
DefImplicitClause ::= [nl] ‘(’ ‘implicit’ DefTermParams ‘)’
95+
DefTermParams ::= DefTermParam {‘,’ DefTermParam}
96+
DefTermParam ::= {Annotation} [‘inline’] Param
97+
Param ::= id ‘:’ ParamType [‘=’ Expr]
98+
```

docs/_docs/reference/syntax.md

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -329,9 +329,6 @@ ArgumentPatterns ::= ‘(’ [Patterns] ‘)’
329329
ClsTypeParamClause::= ‘[’ ClsTypeParam {‘,’ ClsTypeParam} ‘]’
330330
ClsTypeParam ::= {Annotation} [‘+’ | ‘-’] id [HkTypeParamClause] TypeParamBounds
331331
332-
DefTypeParamClause::= ‘[’ DefTypeParam {‘,’ DefTypeParam} ‘]’
333-
DefTypeParam ::= {Annotation} id [HkTypeParamClause] TypeParamBounds
334-
335332
TypTypeParamClause::= ‘[’ TypTypeParam {‘,’ TypTypeParam} ‘]’
336333
TypTypeParam ::= {Annotation} id [HkTypeParamClause] TypeBounds
337334
@@ -343,13 +340,24 @@ ClsParamClause ::= [nl] ‘(’ ClsParams ‘)’
343340
| [nl] ‘(’ ‘using’ (ClsParams | FunArgTypes) ‘)’
344341
ClsParams ::= ClsParam {‘,’ ClsParam}
345342
ClsParam ::= {Annotation} [{Modifier} (‘val’ | ‘var’) | ‘inline’] Param
346-
Param ::= id ‘:’ ParamType [‘=’ Expr]
347343
348-
DefParamClauses ::= {DefParamClause} [[nl] ‘(’ [‘implicit’] DefParams ‘)’]
349-
DefParamClause ::= [nl] ‘(’ DefParams ‘)’ | UsingParamClause
350-
UsingParamClause ::= [nl] ‘(’ ‘using’ (DefParams | FunArgTypes) ‘)’
351-
DefParams ::= DefParam {‘,’ DefParam}
352-
DefParam ::= {Annotation} [‘inline’] Param
344+
DefParamClauses ::= DefParamClause { DefParamClause }
345+
DefParamClause ::= DefTypeParamClause
346+
| DefTermParamClause
347+
| UsingParamClause
348+
TypelessClauses ::= TypelessClause {TypelessClause}
349+
TypelessClause ::= DefTermParamClause
350+
| UsingParamClause
351+
352+
DefTypeParamClause::= [nl] ‘[’ DefTypeParam {‘,’ DefTypeParam} ‘]’
353+
DefTypeParam ::= {Annotation} id [HkTypeParamClause] TypeParamBounds
354+
DefTermParamClause::= [nl] ‘(’ [DefTermParams] ‘)’
355+
UsingParamClause ::= [nl] ‘(’ ‘using’ (DefTermParams | FunArgTypes) ‘)’
356+
DefImplicitClause ::= [nl] ‘(’ ‘implicit’ DefTermParams ‘)’
357+
358+
DefTermParams ::= DefTermParam {‘,’ DefTermParam}
359+
DefTermParam ::= {Annotation} [‘inline’] Param
360+
Param ::= id ‘:’ ParamType [‘=’ Expr]
353361
```
354362

355363
### Bindings and Imports
@@ -400,8 +408,8 @@ Dcl ::= RefineDcl
400408
ValDcl ::= ids ‘:’ Type
401409
VarDcl ::= ids ‘:’ Type
402410
DefDcl ::= DefSig ‘:’ Type
403-
DefSig ::= id [DefTypeParamClause] DefParamClauses
404-
TypeDcl ::= id [TypeParamClause] {FunParamClause} TypeBounds [‘=’ Type]
411+
DefSig ::= id [DefParamClauses] [DefImplicitClause]
412+
TypeDcl ::= id [TypeParamClause] {FunParamClause} TypeBounds
405413
406414
Def ::= ‘val’ PatDef
407415
| ‘var’ PatDef
@@ -411,7 +419,7 @@ Def ::= ‘val’ PatDef
411419
PatDef ::= ids [‘:’ Type] ‘=’ Expr
412420
| Pattern2 [‘:’ Type] ‘=’ Expr
413421
DefDef ::= DefSig [‘:’ Type] ‘=’ Expr
414-
| ‘this’ DefParamClause DefParamClauses ‘=’ ConstrExpr
422+
| ‘this’ TypelessClauses [DefImplicitClause] ‘=’ ConstrExpr
415423
416424
TmplDef ::= ([‘case’] ‘class’ | ‘trait’) ClassDef
417425
| [‘case’] ‘object’ ObjectDef
@@ -423,10 +431,10 @@ ConstrMods ::= {Annotation} [AccessModifier]
423431
ObjectDef ::= id [Template]
424432
EnumDef ::= id ClassConstr InheritClauses EnumBody
425433
GivenDef ::= [GivenSig] (AnnotType [‘=’ Expr] | StructuralInstance)
426-
GivenSig ::= [id] [DefTypeParamClause] {UsingParamClause} ‘:’ -- one of `id`, `DefParamClause`, `UsingParamClause` must be present
434+
GivenSig ::= [id] [DefTypeParamClause] {UsingParamClause} ‘:’ -- one of `id`, `DefTypeParamClause`, `UsingParamClause` must be present
427435
StructuralInstance ::= ConstrApp {‘with’ ConstrApp} [‘with’ WithTemplateBody]
428436
Extension ::= ‘extension’ [DefTypeParamClause] {UsingParamClause}
429-
‘(’ DefParam ‘)’ {UsingParamClause} ExtMethods
437+
‘(’ DefTermParam ‘)’ {UsingParamClause} ExtMethods
430438
ExtMethods ::= ExtMethod | [nl] <<< ExtMethod {semi ExtMethod} >>>
431439
ExtMethod ::= {Annotation [nl]} {Modifier} ‘def’ DefDef
432440
| Export

0 commit comments

Comments
 (0)