Skip to content

Commit 3aedf77

Browse files
committed
Trial balloon for fixes to given syntax
Change contextual docs to reflect three changes to `given` syntax: - put `given` inside the parentheses of parameters and arguments, as was suggested by @smarter. - change given import syntax to make `given` an import selector - change `the` to `theGiven`. All of these should discussed in separate issues.
1 parent 6d500c5 commit 3aedf77

12 files changed

+141
-121
lines changed

docs/docs/internals/syntax.md

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -232,8 +232,8 @@ Quoted ::= ‘'’ ‘{’ Block ‘}’
232232
ExprsInParens ::= ExprInParens {‘,’ ExprInParens}
233233
ExprInParens ::= PostfixExpr ‘:’ Type -- normal Expr allows only RefinedType here
234234
| Expr
235-
ParArgumentExprs ::= ‘(’ ExprsInParens ‘)’ exprs
236-
| ‘(’ [ExprsInParens ‘,’] PostfixExpr ‘:’ ‘_’ ‘*’ ‘)’ exprs :+ Typed(expr, Ident(wildcardStar))
235+
ParArgumentExprs ::= ‘(’ [‘given’] ExprsInParens ‘)’ exprs
236+
| ‘(’ [ExprsInParens ‘,’] PostfixExpr ‘:’ ‘_’ ‘*’ ‘)’ exprs :+ Typed(expr, Ident(wildcardStar))
237237
ArgumentExprs ::= ParArgumentExprs
238238
| [cnl] BlockExpr
239239
BlockExpr ::= ‘{’ CaseClauses | Block ‘}’
@@ -298,7 +298,7 @@ HkTypeParam ::= {Annotation} [‘+’ | ‘-’] (Id[HkTypeParamClause] |
298298
ClsParamClauses ::= {ClsParamClause} [[nl] ‘(’ [‘implicit’] ClsParams ‘)’]
299299
| {ClsParamClause} {GivenClsParamClause}
300300
ClsParamClause ::= [nl] ‘(’ ClsParams ‘)’
301-
GivenClsParamClause::= ‘given’ (‘(’ ClsParams ‘)’ | GivenTypes)
301+
GivenClsParamClause::= ‘(’ ‘given’ (ClsParams | GivenTypes) ‘)’
302302
ClsParams ::= ClsParam {‘,’ ClsParam}
303303
ClsParam ::= {Annotation} ValDef(mods, id, tpe, expr) -- point of mods on val/var
304304
[{Modifier} (‘val’ | ‘var’) | ‘inline’] Param
@@ -308,7 +308,7 @@ Param ::= id ‘:’ ParamType [‘=’ Expr]
308308
DefParamClauses ::= {DefParamClause} [[nl] ‘(’ [‘implicit’] DefParams ‘)’]
309309
| {DefParamClause} {GivenParamClause}
310310
DefParamClause ::= [nl] ‘(’ DefParams ‘)’
311-
GivenParamClause ::= ‘given’ (‘(’ DefParams ‘)’ | GivenTypes)
311+
GivenParamClause ::= ‘(’ ‘given’ (DefParams | GivenTypes) ‘)’
312312
DefParams ::= DefParam {‘,’ DefParam}
313313
DefParam ::= {Annotation} [‘inline’] Param ValDef(mods, id, tpe, expr) -- point of mods at id.
314314
GivenTypes ::= AnnotType {‘,’ AnnotType}
@@ -335,12 +335,16 @@ AccessQualifier ::= ‘[’ (id | ‘this’) ‘]’
335335
336336
Annotation ::= ‘@’ SimpleType {ParArgumentExprs} Apply(tpe, args)
337337
338-
Import ::= ‘import’ [‘given’] ImportExpr {‘,’ ImportExpr}
339-
ImportExpr ::= StableId ‘.’ (id | ‘_’ | ImportSelectors) Import(expr, sels)
340-
ImportSelectors ::= ‘{’ {ImportSelector ‘,’} FinalSelector ‘}’
341-
FinalSelector ::= ImportSelector Ident(name)
342-
| ‘_’ [‘:’ Type] TypeBoundsTree(EmptyTree, tpt)
343-
ImportSelector ::= id [‘=>’ id | ‘=>’ ‘_’]
338+
Import ::= ‘import’ ImportExpr {‘,’ ImportExpr}
339+
ImportExpr ::= StableId ‘.’ ImportSpec Import(expr, sels)
340+
ImportSpec ::= id
341+
| ‘_’
342+
| ‘given’
343+
| ‘{’ ImportSelectors) ‘}’
344+
ImportSelectors ::= [‘given’] id [‘=>’ id | ‘=>’ ‘_’] [‘,’ ImportSelectors]
345+
| WildCardSelector {‘,’ WildCardSelector}
346+
WildCardSelector ::= ‘given’ [‘as’ InfixType]
347+
| ‘_' [‘:’ InfixType]
344348
Export ::= ‘export’ [‘given’] ImportExpr {‘,’ ImportExpr}
345349
```
346350

@@ -382,17 +386,15 @@ ClassConstr ::= [ClsTypeParamClause] [ConstrMods] ClsParamClauses
382386
ConstrMods ::= {Annotation} [AccessModifier]
383387
ObjectDef ::= id [Template] ModuleDef(mods, name, template) // no constructor
384388
EnumDef ::= id ClassConstr InheritClauses EnumBody EnumDef(mods, name, tparams, template)
385-
GivenDef ::= [id] [DefTypeParamClause] GivenBody
386-
GivenBody ::= [‘as’ ConstrApp {‘,’ ConstrApp }] {GivenParamClause} [TemplateBody]
387-
| ‘as’ Type {GivenParamClause} ‘=’ Expr
389+
GivenDef ::= [id] [DefTypeParamClause] {GivenParamClause} GivenBody
390+
GivenBody ::= [‘as’ ConstrApp {‘,’ ConstrApp }] [TemplateBody]
391+
| ‘as’ Type ‘=’ Expr
388392
| ‘(’ DefParam ‘)’ TemplateBody
389393
Template ::= InheritClauses [TemplateBody] Template(constr, parents, self, stats)
390394
InheritClauses ::= [‘extends’ ConstrApps] [‘derives’ QualId {‘,’ QualId}]
391395
ConstrApps ::= ConstrApp {‘with’ ConstrApp}
392396
| ConstrApp {‘,’ ConstrApp}
393-
ConstrApp ::= SimpleConstrApp
394-
| ‘(’ SimpleConstrApp {‘given’ (PrefixExpr | ParArgumentExprs)} ‘)’
395-
SimpleConstrApp ::= AnnotType {ArgumentExprs} Apply(tp, args)
397+
ConstrApp ::= AnnotType {ArgumentExprs} Apply(tp, args)
396398
ConstrExpr ::= SelfInvocation
397399
| ‘{’ SelfInvocation {semi BlockStat} ‘}’
398400
SelfInvocation ::= ‘this’ ArgumentExprs {ArgumentExprs}

docs/docs/reference/contextual/context-bounds.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,13 @@ A context bound is a shorthand for expressing the common pattern of an implicit
99
```scala
1010
def maximum[T: Ord](xs: List[T]): T = xs.reduceLeft(max)
1111
```
12-
A bound like `: Ord` on a type parameter `T` of a method or class indicates an implicit parameter `given Ord[T]`. The implicit parameter(s) generated from context bounds come last in the definition of the containing method or class. E.g.,
12+
A bound like `: Ord` on a type parameter `T` of a method or class indicates an implicit parameter `(given Ord[T])`. The implicit parameter(s) generated from context bounds come last in the definition of the containing method or class. E.g.,
1313
```scala
14-
def f[T: C1 : C2, U: C3](x: T) given (y: U, z: V): R
14+
def f[T: C1 : C2, U: C3](x: T)(given y: U, z: V): R
1515
```
1616
would expand to
1717
```scala
18-
def f[T, U](x: T) given (y: U, z: V) given C1[T], C2[T], C3[U]: R
18+
def f[T, U](x: T)(given y: U, z: V)(given C1[T], C2[T], C3[U]): R
1919
```
2020
Context bounds can be combined with subtype bounds. If both are present, subtype bounds come first, e.g.
2121
```scala

docs/docs/reference/contextual/delegates.md

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ given IntOrd as Ord[Int] {
1818
if (x < y) -1 else if (x > y) +1 else 0
1919
}
2020

21-
given ListOrd[T] as Ord[List[T]] given (ord: Ord[T]) {
21+
given ListOrd[T](given ord: Ord[T]) as Ord[List[T]] {
2222

2323
def compare(xs: List[T], ys: List[T]): Int = (xs, ys) match {
2424
case (Nil, Nil) => 0
@@ -42,7 +42,7 @@ The name of a given instance can be left out. So the definitions
4242
of the last section can also be expressed like this:
4343
```scala
4444
given as Ord[Int] { ... }
45-
given [T] as Ord[List[T]] given Ord[T] { ... }
45+
given [T](given Ord[T]) as Ord[List[T]] { ... }
4646
```
4747
If the name of a given is missing, the compiler will synthesize a name from
4848
the type(s) in the `as` clause.
@@ -61,7 +61,7 @@ returned for this and all subsequent accesses to `global`.
6161
Alias givens can be anonymous, e.g.
6262
```scala
6363
given as Position = enclosingTree.position
64-
given as Context given (outer: Context) = outer.withOwner(currentOwner)
64+
given (given outer: Context) as Context = outer.withOwner(currentOwner)
6565
```
6666
An alias given can have type parameters and given clauses just like any other given instance, but it can only implement a single type.
6767

@@ -78,13 +78,10 @@ Here is the new syntax of given instances, seen as a delta from the [standard co
7878
```
7979
TmplDef ::= ...
8080
| ‘given’ GivenDef
81-
GivenDef ::= [id] [DefTypeParamClause] GivenBody
82-
GivenBody ::= [‘as’ ConstrApp {‘,’ ConstrApp }] {GivenParamClause} [TemplateBody]
83-
| ‘as’ Type {GivenParamClause} ‘=’ Expr
84-
ConstrApp ::= SimpleConstrApp
85-
| ‘(’ SimpleConstrApp {‘given’ (PrefixExpr | ParArgumentExprs)} ‘)’
86-
SimpleConstrApp ::= AnnotType {ArgumentExprs}
87-
GivenParamClause ::= ‘given’ (‘(’ [DefParams] ‘)’ | GivenTypes)
81+
GivenDef ::= [id] [DefTypeParamClause] {GivenParamClause} GivenBody
82+
GivenBody ::= [‘as’ ConstrApp {‘,’ ConstrApp }] [TemplateBody]
83+
| ‘as’ Type ‘=’ Expr
84+
GivenParamClause ::= ‘(’ ‘given’ (DefParams | GivenTypes) ‘)’
8885
GivenTypes ::= AnnotType {‘,’ AnnotType}
8986
```
9087
The identifier `id` can be omitted only if either the `as` part or the template body is present.

docs/docs/reference/contextual/derivation.md

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ derivation support.
4545

4646
/** the type being mirrored */
4747
type MirroredType
48-
48+
4949
/** the type of the elements of the mirrored type */
5050
type MirroredElemTypes
5151

@@ -130,7 +130,7 @@ Note the following properties of `Mirror` types,
130130
possibly parameterized, tuple type. Dotty's metaprogramming facilities can be used to work with these tuple types
131131
as-is, and higher level libraries can be built on top of them.
132132
+ The methods `ordinal` and `fromProduct` are defined in terms of `MirroredMonoType` which is the type of kind-`*`
133-
which is obtained from `MirroredType` by wildcarding its type parameters.
133+
which is obtained from `MirroredType` by wildcarding its type parameters.
134134

135135
### Type classes supporting automatic deriving
136136

@@ -139,7 +139,7 @@ signature and implementation of a `derived` method for a type class `TC[_]` are
139139
following form,
140140

141141
```scala
142-
def derived[T] given Mirror.Of[T]: TC[T] = ...
142+
def derived[T](given Mirror.Of[T]): TC[T] = ...
143143
```
144144

145145
That is, the `derived` method takes a given parameter of (some subtype of) type `Mirror` which defines the shape of
@@ -175,7 +175,7 @@ we need to implement a method `Eq.derived` on the companion object of `Eq` that
175175
a `Mirror[T]`. Here is a possible implementation,
176176

177177
```scala
178-
inline given derived[T] as Eq[T] given (m: Mirror.Of[T]) = {
178+
inline given derived[T](given m: Mirror.Of[T]) as Eq[T] = {
179179
val elemInstances = summonAll[m.MirroredElemTypes] // (1)
180180
inline m match { // (2)
181181
case s: Mirror.SumOf[T] => eqSum(s, elemInstances)
@@ -281,7 +281,7 @@ object Eq {
281281
}
282282
}
283283

284-
inline given derived[T] as Eq[T] given (m: Mirror.Of[T]) = {
284+
inline given derived[T](given m: Mirror.Of[T]) as Eq[T] = {
285285
val elemInstances = summonAll[m.MirroredElemTypes]
286286
inline m match {
287287
case s: Mirror.SumOf[T] => eqSum(s, elemInstances)
@@ -312,11 +312,11 @@ In this case the code that is generated by the inline expansion for the derived
312312
following, after a little polishing,
313313

314314
```scala
315-
given derived$Eq[T] as Eq[Opt[T]] given (eqT: Eq[T]) =
315+
given derived$Eq[T](given eqT: Eq[T]) as Eq[Opt[T]] =
316316
eqSum(the[Mirror[Opt[T]]],
317317
List(
318318
eqProduct(the[Mirror[Sm[T]]], List(the[Eq[T]]))
319-
eqProduct(the[Mirror[Nn.type]], Nil)
319+
eqProduct(the[Mirror[Nn.type]], Nil)
320320
)
321321
)
322322
```
@@ -329,20 +329,20 @@ As a third example, using a higher level library such as shapeless the type clas
329329
`derived` method as,
330330

331331
```scala
332-
given eqSum[A] as Eq[A] given (inst: => K0.CoproductInstances[Eq, A]) {
332+
given eqSum[A](given inst: => K0.CoproductInstances[Eq, A]) as Eq[A] {
333333
def eqv(x: A, y: A): Boolean = inst.fold2(x, y)(false)(
334334
[t] => (eqt: Eq[t], t0: t, t1: t) => eqt.eqv(t0, t1)
335335
)
336336
}
337337

338-
given eqProduct[A] as Eq[A] given (inst: K0.ProductInstances[Eq, A]) {
338+
given eqProduct[A](given inst: K0.ProductInstances[Eq, A]) as Eq[A] {
339339
def eqv(x: A, y: A): Boolean = inst.foldLeft2(x, y)(true: Boolean)(
340340
[t] => (acc: Boolean, eqt: Eq[t], t0: t, t1: t) => Complete(!eqt.eqv(t0, t1))(false)(true)
341341
)
342342
}
343343

344344

345-
inline def derived[A] given (gen: K0.Generic[A]): Eq[A] = gen.derive(eqSum, eqProduct)
345+
inline def derived[A](given gen: K0.Generic[A]): Eq[A] = gen.derive(eqSum, eqProduct)
346346
```
347347

348348
The framework described here enables all three of these approaches without mandating any of them.

docs/docs/reference/contextual/given-clauses.md

Lines changed: 31 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,15 @@ repetitive arguments instead of the programmer having to write them explicitly.
1212
For example, with the [given instances](./delegates.md) defined previously,
1313
a maximum function that works for any arguments for which an ordering exists can be defined as follows:
1414
```scala
15-
def max[T](x: T, y: T) given (ord: Ord[T]): T =
15+
def max[T](x: T, y: T)(given ord: Ord[T]): T =
1616
if (ord.compare(x, y) < 0) y else x
1717
```
1818
Here, `ord` is an _implicit parameter_ introduced with a `given` clause.
1919
The `max` method can be applied as follows:
2020
```scala
21-
max(2, 3) given IntOrd
21+
max(2, 3)(given IntOrd)
2222
```
23-
The `given IntOrd` part passes `IntOrd` as an argument for the `ord` parameter. But the point of
23+
The `(given IntOrd)` part passes `IntOrd` as an argument for the `ord` parameter. But the point of
2424
implicit parameters is that this argument can also be left out (and it usually is). So the following
2525
applications are equally valid:
2626
```scala
@@ -35,65 +35,68 @@ mentioned explicitly at all, since it is used only in synthesized arguments for
3535
other implicit parameters. In that case one can avoid defining a parameter name
3636
and just provide its type. Example:
3737
```scala
38-
def maximum[T](xs: List[T]) given Ord[T]: T =
38+
def maximum[T](xs: List[T])(given Ord[T]): T =
3939
xs.reduceLeft(max)
4040
```
4141
`maximum` takes an implicit parameter of type `Ord` only to pass it on as an
4242
inferred argument to `max`. The name of the parameter is left out.
4343

44-
Generally, implicit parameters may be defined either as a parameter list `(p_1: T_1, ..., p_n: T_n)`
45-
or as a sequence of types, separated by commas.
44+
Generally, implicit parameters may be defined either as a full parameter list `(given p_1: T_1, ..., p_n: T_n)` or just as a sequence of types `(given T_1, ..., T_n)`.
45+
Vararg given parameters are not allowed.
4646

4747
## Inferring Complex Arguments
4848

4949
Here are two other methods that have an implicit parameter of type `Ord[T]`:
5050
```scala
51-
def descending[T] given (asc: Ord[T]): Ord[T] = new Ord[T] {
51+
def descending[T](given asc: Ord[T]): Ord[T] = new Ord[T] {
5252
def compare(x: T, y: T) = asc.compare(y, x)
5353
}
5454

55-
def minimum[T](xs: List[T]) given Ord[T] =
56-
maximum(xs) given descending
55+
def minimum[T](xs: List[T])(given Ord[T]) =
56+
maximum(xs)(given descending)
5757
```
5858
The `minimum` method's right hand side passes `descending` as an explicit argument to `maximum(xs)`.
5959
With this setup, the following calls are all well-formed, and they all normalize to the last one:
6060
```scala
6161
minimum(xs)
62-
maximum(xs) given descending
63-
maximum(xs) given (descending given ListOrd)
64-
maximum(xs) given (descending given (ListOrd given IntOrd))
62+
maximum(xs)(given descending)
63+
maximum(xs)(given descending(given ListOrd))
64+
maximum(xs)(given descending(given ListOrd(given IntOrd)))
6565
```
6666

6767
## Multiple Given Clauses
6868

69-
There can be several given clauses in a definition. Example:
69+
There can be several `given` parameter clauses in a definition and `given` parameter clauses can be freely
70+
mixed with normal ones. Example:
7071
```scala
71-
def f given (u: Universe) given (x: u.Context) = ...
72+
def f(u: Universe)(given c: u.Context)(given s: ctx.Symbol, k: ctx.Kind) = ...
7273
```
73-
However, all `given` clauses in a definition must come after any normal parameter clauses.
7474
Multiple given clauses are matched left-to-right in applications. Example:
7575
```scala
76-
given global as Universe { type Context = ... }
77-
given ctx as global.Context { ... }
76+
object global extends Universe { type Context = ... }
77+
given ctx as global.Context { type Symbol = ...; type Kind = ... }
78+
given sym as ctx.Symbol
79+
given kind as ctx.Kind
7880
```
7981
Then the following calls are all valid (and normalize to the last one)
8082
```scala
8183
f
82-
(f given global)
83-
(f given global) given ctx
84+
f(global)
85+
f(global)(given ctx)
86+
f(global)(given ctx)(given sym, kind)
8487
```
85-
But `f given ctx` would give a type error.
88+
But `f(global)(given sym, kind)` would give a type error.
8689

8790
## Summoning Instances
8891

89-
A method `the` in `Predef` returns the given instance of a specific type. For example,
92+
The method `theGiven` in `Predef` returns the given instance of a specific type. For example,
9093
the given instance for `Ord[List[Int]]` is produced by
9194
```scala
92-
the[Ord[List[Int]]] // reduces to ListOrd given IntOrd
95+
theGiven[Ord[List[Int]]] // reduces to ListOrd given IntOrd
9396
```
94-
The `the` method is simply defined as the (non-widening) identity function over a implicit parameter.
97+
The `theGiven` method is simply defined as the (non-widening) identity function over a implicit parameter.
9598
```scala
96-
def the[T] given (x: T): x.type = x
99+
def theGiven[T](given x: T): x.type = x
97100
```
98101

99102
## Syntax
@@ -102,12 +105,12 @@ Here is the new syntax of parameters and arguments seen as a delta from the [sta
102105
```
103106
ClsParamClauses ::= ...
104107
| {ClsParamClause} {GivenClsParamClause}
105-
GivenClsParamClause ::= ‘given’ (‘(’ ClsParams ‘)’ | GivenTypes)
108+
GivenClsParamClause ::= ‘(’ ‘given’ (ClsParams | GivenTypes) ‘)’
106109
DefParamClauses ::= ...
107110
| {DefParamClause} {GivenParamClause}
108-
GivenParamClause ::= ‘given’ (‘(’ DefParams ‘)’ | GivenTypes)
111+
GivenParamClause ::= ‘(’ ‘given’ (DefParams | GivenTypes) ‘)’
109112
GivenTypes ::= AnnotType {‘,’ AnnotType}
110113
111-
InfixExpr ::= ...
112-
| InfixExpr ‘given’ (InfixExpr | ParArgumentExprs)
114+
ParArgumentExprs ::= ...
115+
| ‘(’ ‘given’ ExprsInParens ‘)’
113116
```

docs/docs/reference/contextual/implicit-by-name-parameters.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ trait Codec[T] {
1212

1313
given intCodec as Codec[Int] = ???
1414

15-
given optionCodec[T] as Codec[Option[T]] given (ev: => Codec[T]) {
15+
given optionCodec[T](given ev: => Codec[T]) as Codec[Option[T]] {
1616
def write(xo: Option[T]) = xo match {
1717
case Some(x) => ev.write(x)
1818
case None =>

0 commit comments

Comments
 (0)