From dbded50aa431858da2e697e7d831eb0dc0fc41db Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 1 Sep 2019 12:42:34 +0200 Subject: [PATCH 1/3] 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. --- docs/docs/internals/syntax.md | 34 ++++++----- .../reference/contextual/context-bounds.md | 6 +- docs/docs/reference/contextual/delegates.md | 17 +++--- docs/docs/reference/contextual/derivation.md | 20 +++---- .../reference/contextual/given-clauses.md | 59 ++++++++++--------- .../contextual/implicit-by-name-parameters.md | 2 +- .../implicit-function-types-spec.md | 17 +++--- .../contextual/implicit-function-types.md | 46 +++++++-------- .../reference/contextual/import-delegate.md | 47 +++++++++++---- .../contextual/multiversal-equality.md | 6 +- .../contextual/relationship-implicits.md | 6 +- docs/docs/reference/contextual/typeclasses.md | 2 +- 12 files changed, 141 insertions(+), 121 deletions(-) diff --git a/docs/docs/internals/syntax.md b/docs/docs/internals/syntax.md index 1d8888698c58..c4aed6a4825e 100644 --- a/docs/docs/internals/syntax.md +++ b/docs/docs/internals/syntax.md @@ -232,8 +232,8 @@ Quoted ::= ‘'’ ‘{’ Block ‘}’ ExprsInParens ::= ExprInParens {‘,’ ExprInParens} ExprInParens ::= PostfixExpr ‘:’ Type -- normal Expr allows only RefinedType here | Expr -ParArgumentExprs ::= ‘(’ ExprsInParens ‘)’ exprs - | ‘(’ [ExprsInParens ‘,’] PostfixExpr ‘:’ ‘_’ ‘*’ ‘)’ exprs :+ Typed(expr, Ident(wildcardStar)) +ParArgumentExprs ::= ‘(’ [‘given’] ExprsInParens ‘)’ exprs + | ‘(’ [ExprsInParens ‘,’] PostfixExpr ‘:’ ‘_’ ‘*’ ‘)’ exprs :+ Typed(expr, Ident(wildcardStar)) ArgumentExprs ::= ParArgumentExprs | [cnl] BlockExpr BlockExpr ::= ‘{’ CaseClauses | Block ‘}’ @@ -298,7 +298,7 @@ HkTypeParam ::= {Annotation} [‘+’ | ‘-’] (Id[HkTypeParamClause] | ClsParamClauses ::= {ClsParamClause} [[nl] ‘(’ [‘implicit’] ClsParams ‘)’] | {ClsParamClause} {GivenClsParamClause} ClsParamClause ::= [nl] ‘(’ ClsParams ‘)’ -GivenClsParamClause::= ‘given’ (‘(’ ClsParams ‘)’ | GivenTypes) +GivenClsParamClause::= ‘(’ ‘given’ (ClsParams | GivenTypes) ‘)’ ClsParams ::= ClsParam {‘,’ ClsParam} ClsParam ::= {Annotation} ValDef(mods, id, tpe, expr) -- point of mods on val/var [{Modifier} (‘val’ | ‘var’) | ‘inline’] Param @@ -308,7 +308,7 @@ Param ::= id ‘:’ ParamType [‘=’ Expr] DefParamClauses ::= {DefParamClause} [[nl] ‘(’ [‘implicit’] DefParams ‘)’] | {DefParamClause} {GivenParamClause} DefParamClause ::= [nl] ‘(’ DefParams ‘)’ -GivenParamClause ::= ‘given’ (‘(’ DefParams ‘)’ | GivenTypes) +GivenParamClause ::= ‘(’ ‘given’ (DefParams | GivenTypes) ‘)’ DefParams ::= DefParam {‘,’ DefParam} DefParam ::= {Annotation} [‘inline’] Param ValDef(mods, id, tpe, expr) -- point of mods at id. GivenTypes ::= AnnotType {‘,’ AnnotType} @@ -335,12 +335,16 @@ AccessQualifier ::= ‘[’ (id | ‘this’) ‘]’ Annotation ::= ‘@’ SimpleType {ParArgumentExprs} Apply(tpe, args) -Import ::= ‘import’ [‘given’] ImportExpr {‘,’ ImportExpr} -ImportExpr ::= StableId ‘.’ (id | ‘_’ | ImportSelectors) Import(expr, sels) -ImportSelectors ::= ‘{’ {ImportSelector ‘,’} FinalSelector ‘}’ -FinalSelector ::= ImportSelector Ident(name) - | ‘_’ [‘:’ Type] TypeBoundsTree(EmptyTree, tpt) -ImportSelector ::= id [‘=>’ id | ‘=>’ ‘_’] +Import ::= ‘import’ ImportExpr {‘,’ ImportExpr} +ImportExpr ::= StableId ‘.’ ImportSpec Import(expr, sels) +ImportSpec ::= id + | ‘_’ + | ‘given’ + | ‘{’ ImportSelectors) ‘}’ +ImportSelectors ::= [‘given’] id [‘=>’ id | ‘=>’ ‘_’] [‘,’ ImportSelectors] + | WildCardSelector {‘,’ WildCardSelector} +WildCardSelector ::= ‘given’ [‘as’ InfixType] + | ‘_' [‘:’ InfixType] Export ::= ‘export’ [‘given’] ImportExpr {‘,’ ImportExpr} ``` @@ -382,17 +386,15 @@ ClassConstr ::= [ClsTypeParamClause] [ConstrMods] ClsParamClauses ConstrMods ::= {Annotation} [AccessModifier] ObjectDef ::= id [Template] ModuleDef(mods, name, template) // no constructor EnumDef ::= id ClassConstr InheritClauses EnumBody EnumDef(mods, name, tparams, template) -GivenDef ::= [id] [DefTypeParamClause] GivenBody -GivenBody ::= [‘as’ ConstrApp {‘,’ ConstrApp }] {GivenParamClause} [TemplateBody] - | ‘as’ Type {GivenParamClause} ‘=’ Expr +GivenDef ::= [id] [DefTypeParamClause] {GivenParamClause} GivenBody +GivenBody ::= [‘as’ ConstrApp {‘,’ ConstrApp }] [TemplateBody] + | ‘as’ Type ‘=’ Expr | ‘(’ DefParam ‘)’ TemplateBody Template ::= InheritClauses [TemplateBody] Template(constr, parents, self, stats) InheritClauses ::= [‘extends’ ConstrApps] [‘derives’ QualId {‘,’ QualId}] ConstrApps ::= ConstrApp {‘with’ ConstrApp} | ConstrApp {‘,’ ConstrApp} -ConstrApp ::= SimpleConstrApp - | ‘(’ SimpleConstrApp {‘given’ (PrefixExpr | ParArgumentExprs)} ‘)’ -SimpleConstrApp ::= AnnotType {ArgumentExprs} Apply(tp, args) +ConstrApp ::= AnnotType {ArgumentExprs} Apply(tp, args) ConstrExpr ::= SelfInvocation | ‘{’ SelfInvocation {semi BlockStat} ‘}’ SelfInvocation ::= ‘this’ ArgumentExprs {ArgumentExprs} diff --git a/docs/docs/reference/contextual/context-bounds.md b/docs/docs/reference/contextual/context-bounds.md index 2593bb355d43..b80285827a50 100644 --- a/docs/docs/reference/contextual/context-bounds.md +++ b/docs/docs/reference/contextual/context-bounds.md @@ -9,13 +9,13 @@ A context bound is a shorthand for expressing the common pattern of an implicit ```scala def maximum[T: Ord](xs: List[T]): T = xs.reduceLeft(max) ``` -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., +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., ```scala -def f[T: C1 : C2, U: C3](x: T) given (y: U, z: V): R +def f[T: C1 : C2, U: C3](x: T)(given y: U, z: V): R ``` would expand to ```scala -def f[T, U](x: T) given (y: U, z: V) given C1[T], C2[T], C3[U]: R +def f[T, U](x: T)(given y: U, z: V)(given C1[T], C2[T], C3[U]): R ``` Context bounds can be combined with subtype bounds. If both are present, subtype bounds come first, e.g. ```scala diff --git a/docs/docs/reference/contextual/delegates.md b/docs/docs/reference/contextual/delegates.md index a3a3b12818bc..0e81f3986a14 100644 --- a/docs/docs/reference/contextual/delegates.md +++ b/docs/docs/reference/contextual/delegates.md @@ -18,7 +18,7 @@ given IntOrd as Ord[Int] { if (x < y) -1 else if (x > y) +1 else 0 } -given ListOrd[T] as Ord[List[T]] given (ord: Ord[T]) { +given ListOrd[T](given ord: Ord[T]) as Ord[List[T]] { def compare(xs: List[T], ys: List[T]): Int = (xs, ys) match { case (Nil, Nil) => 0 @@ -42,7 +42,7 @@ The name of a given instance can be left out. So the definitions of the last section can also be expressed like this: ```scala given as Ord[Int] { ... } -given [T] as Ord[List[T]] given Ord[T] { ... } +given [T](given Ord[T]) as Ord[List[T]] { ... } ``` If the name of a given is missing, the compiler will synthesize a name from the type(s) in the `as` clause. @@ -61,7 +61,7 @@ returned for this and all subsequent accesses to `global`. Alias givens can be anonymous, e.g. ```scala given as Position = enclosingTree.position -given as Context given (outer: Context) = outer.withOwner(currentOwner) +given (given outer: Context) as Context = outer.withOwner(currentOwner) ``` An alias given can have type parameters and given clauses just like any other given instance, but it can only implement a single type. @@ -78,13 +78,10 @@ Here is the new syntax of given instances, seen as a delta from the [standard co ``` TmplDef ::= ... | ‘given’ GivenDef -GivenDef ::= [id] [DefTypeParamClause] GivenBody -GivenBody ::= [‘as’ ConstrApp {‘,’ ConstrApp }] {GivenParamClause} [TemplateBody] - | ‘as’ Type {GivenParamClause} ‘=’ Expr -ConstrApp ::= SimpleConstrApp - | ‘(’ SimpleConstrApp {‘given’ (PrefixExpr | ParArgumentExprs)} ‘)’ -SimpleConstrApp ::= AnnotType {ArgumentExprs} -GivenParamClause ::= ‘given’ (‘(’ [DefParams] ‘)’ | GivenTypes) +GivenDef ::= [id] [DefTypeParamClause] {GivenParamClause} GivenBody +GivenBody ::= [‘as’ ConstrApp {‘,’ ConstrApp }] [TemplateBody] + | ‘as’ Type ‘=’ Expr +GivenParamClause ::= ‘(’ ‘given’ (DefParams | GivenTypes) ‘)’ GivenTypes ::= AnnotType {‘,’ AnnotType} ``` The identifier `id` can be omitted only if either the `as` part or the template body is present. diff --git a/docs/docs/reference/contextual/derivation.md b/docs/docs/reference/contextual/derivation.md index 47f8ef51c307..ea3c7103fd92 100644 --- a/docs/docs/reference/contextual/derivation.md +++ b/docs/docs/reference/contextual/derivation.md @@ -45,7 +45,7 @@ derivation support. /** the type being mirrored */ type MirroredType - + /** the type of the elements of the mirrored type */ type MirroredElemTypes @@ -130,7 +130,7 @@ Note the following properties of `Mirror` types, possibly parameterized, tuple type. Dotty's metaprogramming facilities can be used to work with these tuple types as-is, and higher level libraries can be built on top of them. + The methods `ordinal` and `fromProduct` are defined in terms of `MirroredMonoType` which is the type of kind-`*` - which is obtained from `MirroredType` by wildcarding its type parameters. + which is obtained from `MirroredType` by wildcarding its type parameters. ### Type classes supporting automatic deriving @@ -139,7 +139,7 @@ signature and implementation of a `derived` method for a type class `TC[_]` are following form, ```scala - def derived[T] given Mirror.Of[T]: TC[T] = ... + def derived[T](given Mirror.Of[T]): TC[T] = ... ``` 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 a `Mirror[T]`. Here is a possible implementation, ```scala -inline given derived[T] as Eq[T] given (m: Mirror.Of[T]) = { +inline given derived[T](given m: Mirror.Of[T]) as Eq[T] = { val elemInstances = summonAll[m.MirroredElemTypes] // (1) inline m match { // (2) case s: Mirror.SumOf[T] => eqSum(s, elemInstances) @@ -281,7 +281,7 @@ object Eq { } } - inline given derived[T] as Eq[T] given (m: Mirror.Of[T]) = { + inline given derived[T](given m: Mirror.Of[T]) as Eq[T] = { val elemInstances = summonAll[m.MirroredElemTypes] inline m match { 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 following, after a little polishing, ```scala -given derived$Eq[T] as Eq[Opt[T]] given (eqT: Eq[T]) = +given derived$Eq[T](given eqT: Eq[T]) as Eq[Opt[T]] = eqSum(the[Mirror[Opt[T]]], List( eqProduct(the[Mirror[Sm[T]]], List(the[Eq[T]])) - eqProduct(the[Mirror[Nn.type]], Nil) + eqProduct(the[Mirror[Nn.type]], Nil) ) ) ``` @@ -329,20 +329,20 @@ As a third example, using a higher level library such as shapeless the type clas `derived` method as, ```scala -given eqSum[A] as Eq[A] given (inst: => K0.CoproductInstances[Eq, A]) { +given eqSum[A](given inst: => K0.CoproductInstances[Eq, A]) as Eq[A] { def eqv(x: A, y: A): Boolean = inst.fold2(x, y)(false)( [t] => (eqt: Eq[t], t0: t, t1: t) => eqt.eqv(t0, t1) ) } -given eqProduct[A] as Eq[A] given (inst: K0.ProductInstances[Eq, A]) { +given eqProduct[A](given inst: K0.ProductInstances[Eq, A]) as Eq[A] { def eqv(x: A, y: A): Boolean = inst.foldLeft2(x, y)(true: Boolean)( [t] => (acc: Boolean, eqt: Eq[t], t0: t, t1: t) => Complete(!eqt.eqv(t0, t1))(false)(true) ) } -inline def derived[A] given (gen: K0.Generic[A]): Eq[A] = gen.derive(eqSum, eqProduct) +inline def derived[A](given gen: K0.Generic[A]): Eq[A] = gen.derive(eqSum, eqProduct) ``` The framework described here enables all three of these approaches without mandating any of them. diff --git a/docs/docs/reference/contextual/given-clauses.md b/docs/docs/reference/contextual/given-clauses.md index 020fa95ef7e9..e91bcfc67e7f 100644 --- a/docs/docs/reference/contextual/given-clauses.md +++ b/docs/docs/reference/contextual/given-clauses.md @@ -12,15 +12,15 @@ repetitive arguments instead of the programmer having to write them explicitly. For example, with the [given instances](./delegates.md) defined previously, a maximum function that works for any arguments for which an ordering exists can be defined as follows: ```scala -def max[T](x: T, y: T) given (ord: Ord[T]): T = +def max[T](x: T, y: T)(given ord: Ord[T]): T = if (ord.compare(x, y) < 0) y else x ``` Here, `ord` is an _implicit parameter_ introduced with a `given` clause. The `max` method can be applied as follows: ```scala -max(2, 3) given IntOrd +max(2, 3)(given IntOrd) ``` -The `given IntOrd` part passes `IntOrd` as an argument for the `ord` parameter. But the point of +The `(given IntOrd)` part passes `IntOrd` as an argument for the `ord` parameter. But the point of implicit parameters is that this argument can also be left out (and it usually is). So the following applications are equally valid: ```scala @@ -35,65 +35,68 @@ mentioned explicitly at all, since it is used only in synthesized arguments for other implicit parameters. In that case one can avoid defining a parameter name and just provide its type. Example: ```scala -def maximum[T](xs: List[T]) given Ord[T]: T = +def maximum[T](xs: List[T])(given Ord[T]): T = xs.reduceLeft(max) ``` `maximum` takes an implicit parameter of type `Ord` only to pass it on as an inferred argument to `max`. The name of the parameter is left out. -Generally, implicit parameters may be defined either as a parameter list `(p_1: T_1, ..., p_n: T_n)` -or as a sequence of types, separated by commas. +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)`. +Vararg given parameters are not allowed. ## Inferring Complex Arguments Here are two other methods that have an implicit parameter of type `Ord[T]`: ```scala -def descending[T] given (asc: Ord[T]): Ord[T] = new Ord[T] { +def descending[T](given asc: Ord[T]): Ord[T] = new Ord[T] { def compare(x: T, y: T) = asc.compare(y, x) } -def minimum[T](xs: List[T]) given Ord[T] = - maximum(xs) given descending +def minimum[T](xs: List[T])(given Ord[T]) = + maximum(xs)(given descending) ``` The `minimum` method's right hand side passes `descending` as an explicit argument to `maximum(xs)`. With this setup, the following calls are all well-formed, and they all normalize to the last one: ```scala minimum(xs) -maximum(xs) given descending -maximum(xs) given (descending given ListOrd) -maximum(xs) given (descending given (ListOrd given IntOrd)) +maximum(xs)(given descending) +maximum(xs)(given descending(given ListOrd)) +maximum(xs)(given descending(given ListOrd(given IntOrd))) ``` ## Multiple Given Clauses -There can be several given clauses in a definition. Example: +There can be several `given` parameter clauses in a definition and `given` parameter clauses can be freely +mixed with normal ones. Example: ```scala -def f given (u: Universe) given (x: u.Context) = ... +def f(u: Universe)(given c: u.Context)(given s: ctx.Symbol, k: ctx.Kind) = ... ``` -However, all `given` clauses in a definition must come after any normal parameter clauses. Multiple given clauses are matched left-to-right in applications. Example: ```scala -given global as Universe { type Context = ... } -given ctx as global.Context { ... } +object global extends Universe { type Context = ... } +given ctx as global.Context { type Symbol = ...; type Kind = ... } +given sym as ctx.Symbol +given kind as ctx.Kind ``` Then the following calls are all valid (and normalize to the last one) ```scala f -(f given global) -(f given global) given ctx +f(global) +f(global)(given ctx) +f(global)(given ctx)(given sym, kind) ``` -But `f given ctx` would give a type error. +But `f(global)(given sym, kind)` would give a type error. ## Summoning Instances -A method `the` in `Predef` returns the given instance of a specific type. For example, +The method `theGiven` in `Predef` returns the given instance of a specific type. For example, the given instance for `Ord[List[Int]]` is produced by ```scala -the[Ord[List[Int]]] // reduces to ListOrd given IntOrd +theGiven[Ord[List[Int]]] // reduces to ListOrd given IntOrd ``` -The `the` method is simply defined as the (non-widening) identity function over a implicit parameter. +The `theGiven` method is simply defined as the (non-widening) identity function over a implicit parameter. ```scala -def the[T] given (x: T): x.type = x +def theGiven[T](given x: T): x.type = x ``` ## Syntax @@ -102,12 +105,12 @@ Here is the new syntax of parameters and arguments seen as a delta from the [sta ``` ClsParamClauses ::= ... | {ClsParamClause} {GivenClsParamClause} -GivenClsParamClause ::= ‘given’ (‘(’ ClsParams ‘)’ | GivenTypes) +GivenClsParamClause ::= ‘(’ ‘given’ (ClsParams | GivenTypes) ‘)’ DefParamClauses ::= ... | {DefParamClause} {GivenParamClause} -GivenParamClause ::= ‘given’ (‘(’ DefParams ‘)’ | GivenTypes) +GivenParamClause ::= ‘(’ ‘given’ (DefParams | GivenTypes) ‘)’ GivenTypes ::= AnnotType {‘,’ AnnotType} -InfixExpr ::= ... - | InfixExpr ‘given’ (InfixExpr | ParArgumentExprs) +ParArgumentExprs ::= ... + | ‘(’ ‘given’ ExprsInParens ‘)’ ``` diff --git a/docs/docs/reference/contextual/implicit-by-name-parameters.md b/docs/docs/reference/contextual/implicit-by-name-parameters.md index fa850454d623..d3f815518bc6 100644 --- a/docs/docs/reference/contextual/implicit-by-name-parameters.md +++ b/docs/docs/reference/contextual/implicit-by-name-parameters.md @@ -12,7 +12,7 @@ trait Codec[T] { given intCodec as Codec[Int] = ??? -given optionCodec[T] as Codec[Option[T]] given (ev: => Codec[T]) { +given optionCodec[T](given ev: => Codec[T]) as Codec[Option[T]] { def write(xo: Option[T]) = xo match { case Some(x) => ev.write(x) case None => diff --git a/docs/docs/reference/contextual/implicit-function-types-spec.md b/docs/docs/reference/contextual/implicit-function-types-spec.md index 148f857fabee..d7ef525af829 100644 --- a/docs/docs/reference/contextual/implicit-function-types-spec.md +++ b/docs/docs/reference/contextual/implicit-function-types-spec.md @@ -6,12 +6,12 @@ title: "Implicit Function Types - More Details" ## Syntax Type ::= ... - | `given' FunArgTypes `=>' Type + | `(' `given' FunArgTypes `)' `=>' Type Expr ::= ... - | `given' FunParams `=>' Expr + | `(' `given' FunParams `)' `=>' Expr Implicit function types associate to the right, e.g. -`given S => given T => U` is the same as `given S => (given T => U)`. +`(given S) => (given T) => U` is the same as `(given S) => ((given T) => U)`. ## Implementation @@ -22,13 +22,13 @@ methods with implicit parameters. Specifically, the `N`-ary function type ```scala package scala trait ImplicitFunctionN[-T1 , ... , -TN, +R] { - def apply given (x1: T1 , ... , xN: TN): R + def apply(given x1: T1 , ... , xN: TN): R } ``` Implicit function types erase to normal function types, so these classes are generated on the fly for typechecking, but not realized in actual code. -Implicit function literals `given (x1: T1, ..., xn: Tn) => e` map +Implicit function literals `(given x1: T1, ..., xn: Tn) => e` map implicit parameters `xi` of types `Ti` to the result of evaluating the expression `e`. The scope of each implicit parameter `xi` is `e`. The parameters must have pairwise distinct names. @@ -45,12 +45,9 @@ The implicit function literal is evaluated as the instance creation expression ```scala new scala.ImplicitFunctionN[T1, ..., Tn, T] { - def apply given (x1: T1, ..., xn: Tn): T = e + def apply(given x1: T1, ..., xn: Tn): T = e } ``` -In the case of a single untyped parameter, `given (x) => e` can be -abbreviated to `given x => e`. - An implicit parameter may also be a wildcard represented by an underscore `_`. In that case, a fresh name for the parameter is chosen arbitrarily. @@ -58,7 +55,7 @@ Note: The closing paragraph of the [Anonymous Functions section](https://www.scala-lang.org/files/archive/spec/2.12/06-expressions.html#anonymous-functions) of Scala 2.12 is subsumed by implicit function types and should be removed. -Implicit function literals `given (x1: T1, ..., xn: Tn) => e` are +Implicit function literals `(given x1: T1, ..., xn: Tn) => e` are automatically created for any expression `e` whose expected type is `scala.ImplicitFunctionN[T1, ..., Tn, R]`, unless `e` is itself a implicit function literal. This is analogous to the automatic diff --git a/docs/docs/reference/contextual/implicit-function-types.md b/docs/docs/reference/contextual/implicit-function-types.md index b863871331e5..a50a18f3b4dd 100644 --- a/docs/docs/reference/contextual/implicit-function-types.md +++ b/docs/docs/reference/contextual/implicit-function-types.md @@ -7,7 +7,7 @@ _Implicit functions_ are functions with (only) implicit parameters. Their types are _implicit function types_. Here is an example of an implicit function type: ```scala -type Executable[T] = given ExecutionContext => T +type Executable[T] = (given ExecutionContext) => T ``` An implicit function is applied to synthesized arguments, in the same way a method with a given clause is applied. For instance: @@ -16,14 +16,14 @@ the same way a method with a given clause is applied. For instance: def f(x: Int): Executable[Int] = ... - f(2) given ec // explicit argument + f(2)(given ec) // explicit argument f(2) // argument is inferred ``` Conversely, if the expected type of an expression `E` is an implicit function type -`given (T_1, ..., T_n) => U` and `E` is not already an +`(given T_1, ..., T_n) => U` and `E` is not already an implicit function literal, `E` is converted to an implicit function literal by rewriting to ```scala - given (x_1: T1, ..., x_n: Tn) => E + (given x_1: T1, ..., x_n: Tn) => E ``` where the names `x_1`, ..., `x_n` are arbitrary. This expansion is performed before the expression `E` is typechecked, which means that `x_1`, ..., `x_n` @@ -38,11 +38,11 @@ For example, continuing with the previous definitions, ```scala def g(arg: Executable[Int]) = ... - g(22) // is expanded to g(given ev => 22) + g(22) // is expanded to g((given ev) => 22) - g(f(2)) // is expanded to g(given ev => (f(2) given ev)) + g(f(2)) // is expanded to g((given ev) => f(2)(given ev)) - g(given ctx => f(22) given ctx) // is left as it is + g((given ctx) => f(22)(given ctx)) // is left as it is ``` ### Example: Builder Pattern @@ -82,32 +82,32 @@ Then, the `table`, `row` and `cell` constructor methods can be defined with implicit function types as parameters to avoid the plumbing boilerplate that would otherwise be necessary. ```scala - def table(init: given Table => Unit) = { + def table(init: (given Table) => Unit) = { given t as Table init t } - def row(init: given Row => Unit) given (t: Table) = { + def row(init: (given Row) => Unit)(given t: Table) = { given r as Row init t.add(r) } - def cell(str: String) given (r: Row) = + def cell(str: String)(given r: Row) = r.add(new Cell(str)) ``` With that setup, the table construction code above compiles and expands to: ```scala - table { given ($t: Table) => - row { given ($r: Row) => - cell("top left") given $r - cell("top right") given $r - } given $t - row { given ($r: Row) => - cell("bottom left") given $r - cell("bottom right") given $r - } given $t + table { (given $t: Table) => + row { (given $r: Row) => + cell("top left")(given $r) + cell("top right")(given $r) + } (given $t) + row { (given $r: Row) => + cell("bottom left")(given $r) + cell("bottom right")(given $r) + } (given $t) } ``` ### Example: Postconditions @@ -118,10 +118,10 @@ As a larger example, here is a way to define constructs for checking arbitrary p object PostConditions { opaque type WrappedResult[T] = T - def result[T] given (r: WrappedResult[T]): T = r + def result[T](given r: WrappedResult[T]): T = r - def (x: T) ensuring[T](condition: given WrappedResult[T] => Boolean): T = { - assert(condition given x) + def (x: T) ensuring[T](condition: (given WrappedResult[T]) => Boolean): T = { + assert(condition(given x)) x } } @@ -129,7 +129,7 @@ import PostConditions.{ensuring, result} val s = List(1, 2, 3).sum.ensuring(result == 6) ``` -**Explanations**: We use an implicit function type `given WrappedResult[T] => Boolean` +**Explanations**: We use an implicit function type `(given WrappedResult[T]) => Boolean` as the type of the condition of `ensuring`. An argument to `ensuring` such as `(result == 6)` will therefore have a given instance of type `WrappedResult[T]` in scope to pass along to the `result` method. `WrappedResult` is a fresh type, to make sure diff --git a/docs/docs/reference/contextual/import-delegate.md b/docs/docs/reference/contextual/import-delegate.md index c9be556de9ef..b4c404514038 100644 --- a/docs/docs/reference/contextual/import-delegate.md +++ b/docs/docs/reference/contextual/import-delegate.md @@ -1,9 +1,9 @@ --- layout: doc-page -title: "Given Imports" +title: "Import Given" --- -A special form of import is used to import given instances. Example: +A special form of import selector is used to import given instances. Example: ```scala object A { class TC @@ -12,13 +12,18 @@ object A { } object B { import A._ - import given A._ + import A.given } ``` In the code above, the `import A._` clause of object `B` will import all members -of `A` _except_ the given instance `tc`. Conversely, the second import `import given A._` will import _only_ that given instance. +of `A` _except_ the given instance `tc`. Conversely, the second import `import A.given` will import _only_ that given instance. +The two import clauses can also be merged into one: +```scala +object B: + import A.{given, _} +``` -Generally, a normal import clause brings definitions other than given instances into scope whereas a `given` import brings only given instances into scope. +Generally, a normal import selector brings definitions other than given instances into scope whereas a `given` import selector brings only given instances into scope. There are two main benefits arising from these rules: @@ -34,14 +39,14 @@ There are two main benefits arising from these rules: Since givens can be anonymous it is not always practical to import them by their name, and wildcard imports are typically used instead. By-type imports provide a more specific alternative to wildcard imports, which makes it clearer what is imported. Example: ```scala -import given A.{_: TC} +import A.{given as TC} ``` This imports any given in `A` that has a type which conforms to `TC`. Importing givens of several types `T1,...,Tn` -is expressed by bounding with a union type. +is expressed by multiple `given` selectors. ``` -import given A.{_: T1 | ... | Tn} +import A.{given as T1, ..., given as Tn} ``` -Importing all instances of a parameterized if expressed by wildcard arguments. +Importing all given instances of a parameterized type is expressed by wildcard arguments. For instance, assuming the object ```scala object Instances { @@ -53,13 +58,13 @@ object Instances { ``` the import ```scala -import given Instances.{_: Ordering[?] | ExecutionContext} +import Instances.{given as Ordering[?], given as ExecutionContext} ``` would import the `intOrd`, `listOrd`, and `ec` instances but leave out the `im` instance, since it fits none of the specified bounds. By-type imports can be mixed with by-name imports. If both are present in an import clause, by-type imports come last. For instance, the import clause ```scala -import given Instances.{im, _: Ordering[?]} +import Instances.{given im, given as Ordering[?]} ``` would import `im`, `intOrd`, and `listOrd` but leave out `ec`. @@ -77,13 +82,13 @@ leaves the `isPrimary` method alone. ### Migration -The rules for imports given above have the consequence that a library +The rules for imports stated above have the consequence that a library would have to migrate in lockstep with all its users from old style implicits and normal imports to given instances and imports. The following modifications avoid this hurdle to migration. - 1. An "import given" also brings old style implicits into scope. So, in Scala 3.0 + 1. A `given` import selector also brings old style implicits into scope. So, in Scala 3.0 an old-style implicit definition can be brought into scope either by a normal import or by an import given. 2. In Scala 3.1, old-style implicits accessed through a normal import @@ -95,3 +100,19 @@ The following modifications avoid this hurdle to migration. These rules mean that library users can use `import given` to access old-style implicits in Scala 3.0, and will be gently nudged and then forced to do so in later versions. Libraries can then switch to representation clauses once their user base has migrated. + +### Syntax + +``` +Import ::= ‘import’ ImportExpr {‘,’ ImportExpr} +ImportExpr ::= StableId ‘.’ ImportSpec +ImportSpec ::= id + | ‘_’ + | ‘given’ + | ‘{’ ImportSelectors) ‘}’ +ImportSelectors ::= [‘given’] id [‘=>’ id | ‘=>’ ‘_’] [‘,’ ImportSelectors] + | WildCardSelector {‘,’ WildCardSelector} +WildCardSelector ::= ‘given’ [‘as’ InfixType] + | ‘_' [‘:’ InfixType] +Export ::= ‘export’ ImportExpr {‘,’ ImportExpr} +``` \ No newline at end of file diff --git a/docs/docs/reference/contextual/multiversal-equality.md b/docs/docs/reference/contextual/multiversal-equality.md index 73d481399998..74f2ae30193e 100644 --- a/docs/docs/reference/contextual/multiversal-equality.md +++ b/docs/docs/reference/contextual/multiversal-equality.md @@ -97,7 +97,7 @@ class Box[T](x: T) derives Eql By the usual rules if [typeclass derivation](./derivation.md), this generates the following `Eql` instance in the companion object of `Box`: ```scala -given [T, U] as Eql[Box[T], Box[U]] given Eql[T, U] = Eql.derived +given [T, U](given Eql[T, U]) as Eql[Box[T], Box[U]] = Eql.derived ``` That is, two boxes are comparable with `==` or `!=` if their elements are. Examples: ```scala @@ -178,7 +178,7 @@ This generic version of `contains` is the one used in the current (Scala 2.12) v It looks different but it admits exactly the same applications as the `contains(x: Any)` definition we started with. However, we can make it more useful (i.e. restrictive) by adding an `Eql` parameter: ```scala - def contains[U >: T](x: U) given Eql[T, U]: Boolean // (1) + def contains[U >: T](x: U)(given Eql[T, U]): Boolean // (1) ``` This version of `contains` is equality-safe! More precisely, given `x: T`, `xs: List[T]` and `y: U`, then `xs.contains(y)` is type-correct if and only if @@ -186,7 +186,7 @@ This version of `contains` is equality-safe! More precisely, given Unfortunately, the crucial ability to "lift" equality type checking from simple equality and pattern matching to arbitrary user-defined operations gets lost if we restrict ourselves to an equality class with a single type parameter. Consider the following signature of `contains` with a hypothetical `Eql1[T]` type class: ```scala - def contains[U >: T](x: U) given Eql1[U]: Boolean // (2) + def contains[U >: T](x: U)(given Eql1[U]): Boolean // (2) ``` This version could be applied just as widely as the original `contains(x: Any)` method, since the `Eql1[Any]` fallback is always available! So we have gained nothing. What got lost in the transition to a single parameter type class was the original rule that `Eql[A, B]` is available only if neither `A` nor `B` have a reflexive `Eql` given. That rule simply cannot be expressed if there is a single type parameter for `Eql`. diff --git a/docs/docs/reference/contextual/relationship-implicits.md b/docs/docs/reference/contextual/relationship-implicits.md index 396da6d8c248..248cbafcc44d 100644 --- a/docs/docs/reference/contextual/relationship-implicits.md +++ b/docs/docs/reference/contextual/relationship-implicits.md @@ -21,7 +21,7 @@ Given instances can be mapped to combinations of implicit objects, classes and i ``` 2. Parameterized given instances are mapped to combinations of classes and implicit methods. E.g., ```scala - given ListOrd[T] as Ord[List[T]] given (ord: Ord[T]) { ... } + given ListOrd[T](given (ord: Ord[T]) as Ord[List[T]] { ... } ``` maps to ```scala @@ -73,7 +73,7 @@ gets the synthesized name `second_of_List_T_given`. Given clauses corresponds largely to Scala-2's implicit parameter clauses. E.g. ```scala - def max[T](x: T, y: T) given (ord: Ord[T]): T + def max[T](x: T, y: T)(given ord: Ord[T]): T ``` would be written ```scala @@ -81,7 +81,7 @@ would be written ``` in Scala 2. The main difference concerns applications of such parameters. Explicit arguments to parameters of given clauses _must_ be written using `given`, -mirroring the definition syntax. E.g, `max(2, 3) given IntOrd`. +mirroring the definition syntax. E.g, `max(2, 3)(given IntOrd`). Scala 2 uses normal applications `max(2, 3)(IntOrd)` instead. The Scala 2 syntax has some inherent ambiguities and restrictions which are overcome by the new syntax. For instance, multiple implicit parameter lists are not available in the old syntax, even though they can be simulated using auxiliary objects in the "Aux" pattern. The `the` method corresponds to `implicitly` in Scala 2. diff --git a/docs/docs/reference/contextual/typeclasses.md b/docs/docs/reference/contextual/typeclasses.md index 435320bbe4f0..dae710a86c43 100644 --- a/docs/docs/reference/contextual/typeclasses.md +++ b/docs/docs/reference/contextual/typeclasses.md @@ -17,7 +17,7 @@ trait Monoid[T] extends SemiGroup[T] { def unit: T } object Monoid { - def apply[T] given Monoid[T] = the[Monoid[T]] + def apply[T](given Monoid[T]) = the[Monoid[T]] } given as Monoid[String] { From 6ed305b01400a936c4d0a790dc4190642275bb34 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 9 Sep 2019 10:47:30 +0200 Subject: [PATCH 2/3] Use `:` instead of `as` Following the discussion in #7151, choose `:` instead of `as` for given clauses. --- docs/docs/reference/contextual/conversions.md | 12 +++--- docs/docs/reference/contextual/delegates.md | 31 +++++++------- docs/docs/reference/contextual/derivation.md | 20 ++++----- .../reference/contextual/extension-methods.md | 2 +- .../reference/contextual/given-clauses.md | 6 +-- .../contextual/implicit-by-name-parameters.md | 8 ++-- .../contextual/implicit-function-types.md | 6 +-- .../reference/contextual/import-delegate.md | 42 +++++++++---------- .../contextual/multiversal-equality.md | 12 +++--- .../contextual/relationship-implicits.md | 24 +++++------ docs/docs/reference/contextual/typeclasses.md | 8 ++-- 11 files changed, 85 insertions(+), 86 deletions(-) diff --git a/docs/docs/reference/contextual/conversions.md b/docs/docs/reference/contextual/conversions.md index 255bde2fd665..6b1ccc8fbbb3 100644 --- a/docs/docs/reference/contextual/conversions.md +++ b/docs/docs/reference/contextual/conversions.md @@ -10,13 +10,13 @@ abstract class Conversion[-T, +U] extends (T => U) ``` For example, here is an implicit conversion from `String` to `Token`: ```scala -given as Conversion[String, Token] { +given Conversion[String, Token] { def apply(str: String): Token = new KeyWord(str) } ``` Using an alias this can be expressed more concisely as: ```scala -given as Conversion[String, Token] = new KeyWord(_) +given Conversion[String, Token] = new KeyWord(_) ``` An implicit conversion is applied automatically by the compiler in three situations: @@ -37,7 +37,7 @@ If such an instance `C` is given, the expression `e` is replaced by `C.apply(e)` primitive number types to subclasses of `java.lang.Number`. For instance, the conversion from `Int` to `java.lang.Integer` can be defined as follows: ```scala -given int2Integer as Conversion[Int, java.lang.Integer] = +given int2Integer: Conversion[Int, java.lang.Integer] = java.lang.Integer.valueOf(_) ``` @@ -59,9 +59,9 @@ object Completions { // // CompletionArg.fromStatusCode(statusCode) - given fromString as Conversion[String, CompletionArg] = Error(_) - given fromFuture as Conversion[Future[HttpResponse], CompletionArg] = Response(_) - given fromStatusCode as Conversion[Future[StatusCode], CompletionArg] = Status(_) + given fromString : Conversion[String, CompletionArg] = Error(_) + given fromFuture : Conversion[Future[HttpResponse], CompletionArg] = Response(_) + given fromStatusCode : Conversion[Future[StatusCode], CompletionArg] = Status(_) } import CompletionArg._ diff --git a/docs/docs/reference/contextual/delegates.md b/docs/docs/reference/contextual/delegates.md index 0e81f3986a14..a468559bd0a6 100644 --- a/docs/docs/reference/contextual/delegates.md +++ b/docs/docs/reference/contextual/delegates.md @@ -13,12 +13,12 @@ trait Ord[T] { def (x: T) > (y: T) = compare(x, y) > 0 } -given IntOrd as Ord[Int] { +given intOrd: Ord[Int] { def compare(x: Int, y: Int) = if (x < y) -1 else if (x > y) +1 else 0 } -given ListOrd[T](given ord: Ord[T]) as Ord[List[T]] { +given listOrd[T](given ord: Ord[T]): Ord[List[T]] { def compare(xs: List[T], ys: List[T]): Int = (xs, ys) match { case (Nil, Nil) => 0 @@ -30,10 +30,10 @@ given ListOrd[T](given ord: Ord[T]) as Ord[List[T]] { } } ``` -This code defines a trait `Ord` with two given instances. `IntOrd` defines -a given for the type `Ord[Int]` whereas `ListOrd[T]` defines givens +This code defines a trait `Ord` with two given instances. `intOrd` defines +a given for the type `Ord[Int]` whereas `listOrd[T]` defines givens for `Ord[List[T]]` for all types `T` that come with a given instance for `Ord[T]` themselves. -The `given (ord: Ord[T])` clause in `ListOrd` defines an implicit parameter. +The `(given ord: Ord[T])` clause in `listOrd` defines an implicit parameter. Given clauses are further explained in the [next section](./given-clauses.md). ## Anonymous Given Instances @@ -41,8 +41,8 @@ Given clauses are further explained in the [next section](./given-clauses.md). The name of a given instance can be left out. So the definitions of the last section can also be expressed like this: ```scala -given as Ord[Int] { ... } -given [T](given Ord[T]) as Ord[List[T]] { ... } +given Ord[Int] { ... } +given [T](given Ord[T]): Ord[List[T]] { ... } ``` If the name of a given is missing, the compiler will synthesize a name from the type(s) in the `as` clause. @@ -51,7 +51,7 @@ the type(s) in the `as` clause. An alias can be used to define a given instance that is equal to some expression. E.g.: ```scala -given global as ExecutionContext = new ForkJoinPool() +given global: ExecutionContext = new ForkJoinPool() ``` This creates a given `global` of type `ExecutionContext` that resolves to the right hand side `new ForkJoinPool()`. @@ -60,8 +60,8 @@ returned for this and all subsequent accesses to `global`. Alias givens can be anonymous, e.g. ```scala -given as Position = enclosingTree.position -given (given outer: Context) as Context = outer.withOwner(currentOwner) +given Position = enclosingTree.position +given (given outer: Context): Context = outer.withOwner(currentOwner) ``` An alias given can have type parameters and given clauses just like any other given instance, but it can only implement a single type. @@ -78,11 +78,12 @@ Here is the new syntax of given instances, seen as a delta from the [standard co ``` TmplDef ::= ... | ‘given’ GivenDef -GivenDef ::= [id] [DefTypeParamClause] {GivenParamClause} GivenBody -GivenBody ::= [‘as’ ConstrApp {‘,’ ConstrApp }] [TemplateBody] - | ‘as’ Type ‘=’ Expr +GivenDef ::= GivenBody + | [id] [DefTypeParamClause] {GivenParamClause} + (‘:’ GivenBody | ‘<:’ Type ‘=’ Expr) +GivenBody ::= [ConstrApp {‘,’ ConstrApp }] [TemplateBody] + | Type ‘=’ Expr GivenParamClause ::= ‘(’ ‘given’ (DefParams | GivenTypes) ‘)’ GivenTypes ::= AnnotType {‘,’ AnnotType} ``` -The identifier `id` can be omitted only if either the `as` part or the template body is present. -If the `as` part is missing, the template body must define at least one extension method. +The identifier `id` can be omitted only if some types are implemented or the template body defines at least one extension method. diff --git a/docs/docs/reference/contextual/derivation.md b/docs/docs/reference/contextual/derivation.md index ea3c7103fd92..82a8b06da0e7 100644 --- a/docs/docs/reference/contextual/derivation.md +++ b/docs/docs/reference/contextual/derivation.md @@ -19,9 +19,9 @@ The `derives` clause generates the following given instances for the `Eq`, `Orde companion object of `Tree`, ```scala -given [T: Eq] as Eq[Tree[T]] = Eq.derived -given [T: Ordering] as Ordering[Tree] = Ordering.derived -given [T: Show] as Show[Tree] = Show.derived +given [T: Eq] : Eq[Tree[T]] = Eq.derived +given [T: Ordering] : Ordering[Tree] = Ordering.derived +given [T: Show] : Show[Tree] = Show.derived ``` We say that `Tree` is the _deriving type_ and that the `Eq`, `Ordering` and `Show` instances are _derived instances_. @@ -175,7 +175,7 @@ we need to implement a method `Eq.derived` on the companion object of `Eq` that a `Mirror[T]`. Here is a possible implementation, ```scala -inline given derived[T](given m: Mirror.Of[T]) as Eq[T] = { +inline given derived[T](given m: Mirror.Of[T]): Eq[T] = { val elemInstances = summonAll[m.MirroredElemTypes] // (1) inline m match { // (2) case s: Mirror.SumOf[T] => eqSum(s, elemInstances) @@ -256,7 +256,7 @@ trait Eq[T] { } object Eq { - given as Eq[Int] { + given Eq[Int] { def eqv(x: Int, y: Int) = x == y } @@ -281,7 +281,7 @@ object Eq { } } - inline given derived[T](given m: Mirror.Of[T]) as Eq[T] = { + inline given derived[T](given m: Mirror.Of[T]): Eq[T] = { val elemInstances = summonAll[m.MirroredElemTypes] inline m match { case s: Mirror.SumOf[T] => eqSum(s, elemInstances) @@ -312,7 +312,7 @@ In this case the code that is generated by the inline expansion for the derived following, after a little polishing, ```scala -given derived$Eq[T](given eqT: Eq[T]) as Eq[Opt[T]] = +given derived$Eq[T](given eqT: Eq[T]): Eq[Opt[T]] = eqSum(the[Mirror[Opt[T]]], List( eqProduct(the[Mirror[Sm[T]]], List(the[Eq[T]])) @@ -329,13 +329,13 @@ As a third example, using a higher level library such as shapeless the type clas `derived` method as, ```scala -given eqSum[A](given inst: => K0.CoproductInstances[Eq, A]) as Eq[A] { +given eqSum[A](given inst: => K0.CoproductInstances[Eq, A]): Eq[A] { def eqv(x: A, y: A): Boolean = inst.fold2(x, y)(false)( [t] => (eqt: Eq[t], t0: t, t1: t) => eqt.eqv(t0, t1) ) } -given eqProduct[A](given inst: K0.ProductInstances[Eq, A]) as Eq[A] { +given eqProduct[A](given inst: K0.ProductInstances[Eq, A]): Eq[A] { def eqv(x: A, y: A): Boolean = inst.foldLeft2(x, y)(true: Boolean)( [t] => (acc: Boolean, eqt: Eq[t], t0: t, t1: t) => Complete(!eqt.eqv(t0, t1))(false)(true) ) @@ -354,7 +354,7 @@ change the code of the ADT itself. To do this, simply define an instance using as right-hand side. E.g, to implement `Ordering` for `Option` define, ```scala -given [T: Ordering] as Ordering[Option[T]] = Ordering.derived +given [T: Ordering] : Ordering[Option[T]] = Ordering.derived ``` Assuming the `Ordering.derived` method has a given parameter of type `Mirror[T]` it will be satisfied by the diff --git a/docs/docs/reference/contextual/extension-methods.md b/docs/docs/reference/contextual/extension-methods.md index 653eb0c98a20..40d9c4dea3fd 100644 --- a/docs/docs/reference/contextual/extension-methods.md +++ b/docs/docs/reference/contextual/extension-methods.md @@ -50,7 +50,7 @@ trait StringSeqOps { ``` We can make the extension method available by defining a given `StringSeqOps` instance, like this: ```scala -given ops1 as StringSeqOps +given ops1: StringSeqOps ``` Then ```scala diff --git a/docs/docs/reference/contextual/given-clauses.md b/docs/docs/reference/contextual/given-clauses.md index e91bcfc67e7f..6ecb80a2dc06 100644 --- a/docs/docs/reference/contextual/given-clauses.md +++ b/docs/docs/reference/contextual/given-clauses.md @@ -74,9 +74,9 @@ def f(u: Universe)(given c: u.Context)(given s: ctx.Symbol, k: ctx.Kind) = ... Multiple given clauses are matched left-to-right in applications. Example: ```scala object global extends Universe { type Context = ... } -given ctx as global.Context { type Symbol = ...; type Kind = ... } -given sym as ctx.Symbol -given kind as ctx.Kind +given ctx : global.Context { type Symbol = ...; type Kind = ... } +given sym : ctx.Symbol +given kind : ctx.Kind ``` Then the following calls are all valid (and normalize to the last one) ```scala diff --git a/docs/docs/reference/contextual/implicit-by-name-parameters.md b/docs/docs/reference/contextual/implicit-by-name-parameters.md index d3f815518bc6..9fbd90fc1b27 100644 --- a/docs/docs/reference/contextual/implicit-by-name-parameters.md +++ b/docs/docs/reference/contextual/implicit-by-name-parameters.md @@ -10,9 +10,9 @@ trait Codec[T] { def write(x: T): Unit } -given intCodec as Codec[Int] = ??? +given intCodec: Codec[Int] = ??? -given optionCodec[T](given ev: => Codec[T]) as Codec[Option[T]] { +given optionCodec[T](given ev: => Codec[T]): Codec[Option[T]] { def write(xo: Option[T]) = xo match { case Some(x) => ev.write(x) case None => @@ -36,7 +36,7 @@ The precise steps for synthesizing an argument for an implicit by-name parameter 1. Create a new given instance of type `T`: ```scala - given lv as T = ??? + given lv: T = ??? ``` where `lv` is an arbitrary fresh name. @@ -46,7 +46,7 @@ The precise steps for synthesizing an argument for an implicit by-name parameter ```scala - { given lv as T = E; lv } + { given lv: T = E; lv } ``` Otherwise, return `E` unchanged. diff --git a/docs/docs/reference/contextual/implicit-function-types.md b/docs/docs/reference/contextual/implicit-function-types.md index a50a18f3b4dd..63d8f764de20 100644 --- a/docs/docs/reference/contextual/implicit-function-types.md +++ b/docs/docs/reference/contextual/implicit-function-types.md @@ -12,7 +12,7 @@ type Executable[T] = (given ExecutionContext) => T An implicit function is applied to synthesized arguments, in the same way a method with a given clause is applied. For instance: ```scala - given ec as ExecutionContext = ... + given ec: ExecutionContext = ... def f(x: Int): Executable[Int] = ... @@ -83,13 +83,13 @@ with implicit function types as parameters to avoid the plumbing boilerplate that would otherwise be necessary. ```scala def table(init: (given Table) => Unit) = { - given t as Table + given t: Table init t } def row(init: (given Row) => Unit)(given t: Table) = { - given r as Row + given r: Row init t.add(r) } diff --git a/docs/docs/reference/contextual/import-delegate.md b/docs/docs/reference/contextual/import-delegate.md index b4c404514038..ddf1bdaead61 100644 --- a/docs/docs/reference/contextual/import-delegate.md +++ b/docs/docs/reference/contextual/import-delegate.md @@ -3,12 +3,12 @@ layout: doc-page title: "Import Given" --- -A special form of import selector is used to import given instances. Example: +A special form of import wildcard selector is used to import given instances. Example: ```scala object A { class TC - given tc as TC - def f where TC = ??? + given tc: TC + def f(given TC) = ??? } object B { import A._ @@ -19,16 +19,16 @@ In the code above, the `import A._` clause of object `B` will import all members of `A` _except_ the given instance `tc`. Conversely, the second import `import A.given` will import _only_ that given instance. The two import clauses can also be merged into one: ```scala -object B: +object B import A.{given, _} ``` -Generally, a normal import selector brings definitions other than given instances into scope whereas a `given` import selector brings only given instances into scope. +Generally, a normal wildcard selector `_` brings all definitions other than given instances into scope whereas a `given` selector brings all given instances into scope. There are two main benefits arising from these rules: - It is made clearer where givens in scope are coming from. - In particular, it is not possible to hide imported givens in a long list of regular imports. + In particular, it is not possible to hide imported givens in a long list of regular wildcard imports. - It enables importing all givens without importing anything else. This is particularly important since givens can be anonymous, so the usual recourse of using named imports is not @@ -39,32 +39,32 @@ There are two main benefits arising from these rules: Since givens can be anonymous it is not always practical to import them by their name, and wildcard imports are typically used instead. By-type imports provide a more specific alternative to wildcard imports, which makes it clearer what is imported. Example: ```scala -import A.{given as TC} +import A.{given TC} ``` This imports any given in `A` that has a type which conforms to `TC`. Importing givens of several types `T1,...,Tn` is expressed by multiple `given` selectors. ``` -import A.{given as T1, ..., given as Tn} +import A.{given T1, ..., given Tn} ``` Importing all given instances of a parameterized type is expressed by wildcard arguments. For instance, assuming the object ```scala object Instances { - given intOrd as Ordering[Int] - given [T: Ordering] listOrd as Ordering[List[T]] - given ec as ExecutionContext = ... - given im as Monoid[Int] + given intOrd: Ordering[Int] + given [T: Ordering] listOrd: Ordering[List[T]] + given ec: ExecutionContext = ... + given im: Monoid[Int] } ``` the import ```scala -import Instances.{given as Ordering[?], given as ExecutionContext} +import Instances.{given Ordering[?], given ExecutionContext} ``` would import the `intOrd`, `listOrd`, and `ec` instances but leave out the `im` instance, since it fits none of the specified bounds. By-type imports can be mixed with by-name imports. If both are present in an import clause, by-type imports come last. For instance, the import clause ```scala -import Instances.{given im, given as Ordering[?]} +import Instances.{im, given Ordering[?]} ``` would import `im`, `intOrd`, and `listOrd` but leave out `ec`. @@ -89,15 +89,13 @@ normal imports to given instances and imports. The following modifications avoid this hurdle to migration. 1. A `given` import selector also brings old style implicits into scope. So, in Scala 3.0 - an old-style implicit definition can be brought into scope either by a normal import or by an import given. + an old-style implicit definition can be brought into scope either by a `_` wildcard import or by a `given` import. - 2. In Scala 3.1, old-style implicits accessed through a normal import - will give a deprecation warning. + 2. In Scala 3.1, old-style implicits accessed through a `_` wildcard import will give a deprecation warning. - 3. In some version after 3.1, old-style implicits accessed through a normal import - will give a compiler error. + 3. In some version after 3.1, old-style implicits accessed through a `_` wildcard import will give a compiler error. -These rules mean that library users can use `import given` to access old-style implicits in Scala 3.0, +These rules mean that library users can use `given` imports to access old-style implicits in Scala 3.0, and will be gently nudged and then forced to do so in later versions. Libraries can then switch to representation clauses once their user base has migrated. @@ -110,9 +108,9 @@ ImportSpec ::= id | ‘_’ | ‘given’ | ‘{’ ImportSelectors) ‘}’ -ImportSelectors ::= [‘given’] id [‘=>’ id | ‘=>’ ‘_’] [‘,’ ImportSelectors] +ImportSelectors ::= id [‘=>’ id | ‘=>’ ‘_’] [‘,’ ImportSelectors] | WildCardSelector {‘,’ WildCardSelector} -WildCardSelector ::= ‘given’ [‘as’ InfixType] +WildCardSelector ::= ‘given’ [InfixType] | ‘_' [‘:’ InfixType] Export ::= ‘export’ ImportExpr {‘,’ ImportExpr} ``` \ No newline at end of file diff --git a/docs/docs/reference/contextual/multiversal-equality.md b/docs/docs/reference/contextual/multiversal-equality.md index 74f2ae30193e..933280218ebd 100644 --- a/docs/docs/reference/contextual/multiversal-equality.md +++ b/docs/docs/reference/contextual/multiversal-equality.md @@ -33,7 +33,7 @@ class T derives Eql ``` Alternatively, one can also provide an `Eql` given instance directly, like this: ```scala -given as Eql[T, T] = Eql.derived +given Eql[T, T] = Eql.derived ``` This definition effectively says that values of type `T` can (only) be compared to other values of type `T` when using `==` or `!=`. The definition @@ -59,10 +59,10 @@ definitions below make values of type `A` and type `B` comparable with each other, but not comparable to anything else: ```scala -given as Eql[A, A] = Eql.derived -given as Eql[B, B] = Eql.derived -given as Eql[A, B] = Eql.derived -given as Eql[B, A] = Eql.derived +given Eql[A, A] = Eql.derived +given Eql[B, B] = Eql.derived +given Eql[A, B] = Eql.derived +given Eql[B, A] = Eql.derived ``` The `scala.Eql` object defines a number of `Eql` givens that together define a rule book for what standard types can be compared (more details below). @@ -97,7 +97,7 @@ class Box[T](x: T) derives Eql By the usual rules if [typeclass derivation](./derivation.md), this generates the following `Eql` instance in the companion object of `Box`: ```scala -given [T, U](given Eql[T, U]) as Eql[Box[T], Box[U]] = Eql.derived +given [T, U](given Eql[T, U]) : Eql[Box[T], Box[U]] = Eql.derived ``` That is, two boxes are comparable with `==` or `!=` if their elements are. Examples: ```scala diff --git a/docs/docs/reference/contextual/relationship-implicits.md b/docs/docs/reference/contextual/relationship-implicits.md index 248cbafcc44d..51825dd25798 100644 --- a/docs/docs/reference/contextual/relationship-implicits.md +++ b/docs/docs/reference/contextual/relationship-implicits.md @@ -13,7 +13,7 @@ Given instances can be mapped to combinations of implicit objects, classes and i 1. Given instances without parameters are mapped to implicit objects. E.g., ```scala - given IntOrd as Ord[Int] { ... } + given intOrd: Ord[Int] { ... } ``` maps to ```scala @@ -21,7 +21,7 @@ Given instances can be mapped to combinations of implicit objects, classes and i ``` 2. Parameterized given instances are mapped to combinations of classes and implicit methods. E.g., ```scala - given ListOrd[T](given (ord: Ord[T]) as Ord[List[T]] { ... } + given listOrd[T](given (ord: Ord[T]): Ord[List[T]] { ... } ``` maps to ```scala @@ -35,10 +35,10 @@ Given instances can be mapped to combinations of implicit objects, classes and i Examples: ```scala - given global as ExecutionContext = new ForkJoinContext() + given global: ExecutionContext = new ForkJoinContext() val ctx: Context - given as Context = ctx + given Context = ctx ``` would map to ```scala @@ -50,14 +50,14 @@ Given instances can be mapped to combinations of implicit objects, classes and i Anonymous given instances get compiler synthesized names, which are generated in a reproducible way from the implemented type(s). For example, if the names of the `IntOrd` and `ListOrd` givens above were left out, the following names would be synthesized instead: ```scala - given Ord_Int_given as Ord[Int] { ... } - given Ord_List_given[T] as Ord[List[T]] { ... } + given given_Ord_Int : Ord[Int] { ... } + given given_Ord_List[T] : Ord[List[T]] { ... } ``` The synthesized type names are formed from + - the prefix `given_`, - the simple name(s) of the implemented type(s), leaving out any prefixes, - - the simple name(s) of the toplevel argument type constructors to these types - - the suffix `_given`. + - the simple name(s) of the toplevel argument type constructors to these types. Anonymous given instances that define extension methods without also implementing a type get their name from the name of the first extension method and the toplevel type @@ -67,7 +67,7 @@ constructor of its first parameter. For example, the given instance def (xs: List[T]) second[T] = ... } ``` -gets the synthesized name `second_of_List_T_given`. +gets the synthesized name `given_second_of_List_T`. ### Given Clauses @@ -134,7 +134,7 @@ Implicit conversion methods in Scala 2 can be expressed as given instances of th ``` one can write ```scala - given stringToToken as Conversion[String, Token] { + given stringToToken: Conversion[String, Token] { def apply(str: String): Token = new KeyWord(str) } ``` @@ -153,7 +153,7 @@ E.g., Scala 2's can be expressed in Dotty as ```scala lazy val pos: Position = tree.sourcePos - given as Position = pos + given Position = pos ``` ### Abstract Implicits @@ -165,7 +165,7 @@ An abstract implicit `val` or `def` in Scala 2 can be expressed in Dotty using a can be expressed in Dotty as ```scala def symDeco: SymDeco - given as SymDeco = symDeco + given SymDeco = symDeco ``` ## Implementation Status and Timeline diff --git a/docs/docs/reference/contextual/typeclasses.md b/docs/docs/reference/contextual/typeclasses.md index dae710a86c43..06a39b30f7c7 100644 --- a/docs/docs/reference/contextual/typeclasses.md +++ b/docs/docs/reference/contextual/typeclasses.md @@ -20,12 +20,12 @@ object Monoid { def apply[T](given Monoid[T]) = the[Monoid[T]] } -given as Monoid[String] { +given Monoid[String] { def (x: String) combine (y: String): String = x.concat(y) def unit: String = "" } -given as Monoid[Int] { +given Monoid[Int] { def (x: Int) combine (y: Int): Int = x + y def unit: Int = 0 } @@ -48,14 +48,14 @@ trait Monad[F[_]] extends Functor[F] { def pure[A](x: A): F[A] } -given ListMonad as Monad[List] { +given listMonad: Monad[List] { def (xs: List[A]) flatMap [A, B] (f: A => List[B]): List[B] = xs.flatMap(f) def pure[A](x: A): List[A] = List(x) } -given ReaderMonad[Ctx] as Monad[[X] =>> Ctx => X] { +given readerMonad[Ctx]: Monad[[X] =>> Ctx => X] { def (r: Ctx => A) flatMap [A, B] (f: A => Ctx => B): Ctx => B = ctx => f(r(ctx))(ctx) def pure[A](x: A): Ctx => A = From 685cb7961e0e45d40f083e3bc09b465de44e05f4 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 9 Sep 2019 22:21:05 +0200 Subject: [PATCH 3/3] Rename `the` to `summon` --- docs/docs/reference/contextual/derivation.md | 8 ++++---- docs/docs/reference/contextual/extension-methods.md | 2 +- docs/docs/reference/contextual/given-clauses.md | 8 ++++---- .../reference/contextual/implicit-by-name-parameters.md | 4 ++-- docs/docs/reference/contextual/typeclasses.md | 2 +- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/docs/reference/contextual/derivation.md b/docs/docs/reference/contextual/derivation.md index 82a8b06da0e7..fc4506c4e526 100644 --- a/docs/docs/reference/contextual/derivation.md +++ b/docs/docs/reference/contextual/derivation.md @@ -301,7 +301,7 @@ enum Opt[+T] derives Eq { object Test extends App { import Opt._ - val eqoi = the[Eq[Opt[Int]]] + val eqoi = summon[Eq[Opt[Int]]] assert(eqoi.eqv(Sm(23), Sm(23))) assert(!eqoi.eqv(Sm(23), Sm(13))) assert(!eqoi.eqv(Sm(23), Nn)) @@ -313,10 +313,10 @@ following, after a little polishing, ```scala given derived$Eq[T](given eqT: Eq[T]): Eq[Opt[T]] = - eqSum(the[Mirror[Opt[T]]], + eqSum(summon[Mirror[Opt[T]]], List( - eqProduct(the[Mirror[Sm[T]]], List(the[Eq[T]])) - eqProduct(the[Mirror[Nn.type]], Nil) + eqProduct(summon[Mirror[Sm[T]]], List(summon[Eq[T]])) + eqProduct(summon[Mirror[Nn.type]], Nil) ) ) ``` diff --git a/docs/docs/reference/contextual/extension-methods.md b/docs/docs/reference/contextual/extension-methods.md index 40d9c4dea3fd..1fe324dd5315 100644 --- a/docs/docs/reference/contextual/extension-methods.md +++ b/docs/docs/reference/contextual/extension-methods.md @@ -155,7 +155,7 @@ def (xs: List[List[T]]) flattened [T] = xs.foldLeft[List[T]](Nil)(_ ++ _) def (x: T) + [T : Numeric](y: T): T = - the[Numeric[T]].plus(x, y) + summon[Numeric[T]].plus(x, y) ``` As usual, type parameters of the extension method follow the defined method name. Nevertheless, such type parameters can already be used in the preceding parameter clause. diff --git a/docs/docs/reference/contextual/given-clauses.md b/docs/docs/reference/contextual/given-clauses.md index 6ecb80a2dc06..aa9c8b86ea33 100644 --- a/docs/docs/reference/contextual/given-clauses.md +++ b/docs/docs/reference/contextual/given-clauses.md @@ -89,14 +89,14 @@ But `f(global)(given sym, kind)` would give a type error. ## Summoning Instances -The method `theGiven` in `Predef` returns the given instance of a specific type. For example, +The method `summon` in `Predef` returns the given instance of a specific type. For example, the given instance for `Ord[List[Int]]` is produced by ```scala -theGiven[Ord[List[Int]]] // reduces to ListOrd given IntOrd +summon[Ord[List[Int]]] // reduces to ListOrd given IntOrd ``` -The `theGiven` method is simply defined as the (non-widening) identity function over a implicit parameter. +The `summon` method is simply defined as the (non-widening) identity function over a implicit parameter. ```scala -def theGiven[T](given x: T): x.type = x +def summon[T](given x: T): x.type = x ``` ## Syntax diff --git a/docs/docs/reference/contextual/implicit-by-name-parameters.md b/docs/docs/reference/contextual/implicit-by-name-parameters.md index 9fbd90fc1b27..e98ad96fca8b 100644 --- a/docs/docs/reference/contextual/implicit-by-name-parameters.md +++ b/docs/docs/reference/contextual/implicit-by-name-parameters.md @@ -19,7 +19,7 @@ given optionCodec[T](given ev: => Codec[T]): Codec[Option[T]] { } } -val s = the[Codec[Option[Int]]] +val s = summon[Codec[Option[Int]]] s.write(Some(33)) s.write(None) @@ -54,7 +54,7 @@ The precise steps for synthesizing an argument for an implicit by-name parameter In the example above, the definition of `s` would be expanded as follows. ```scala -val s = the[Test.Codec[Option[Int]]]( +val s = summon[Test.Codec[Option[Int]]]( optionCodec[Int](intCodec) ) ``` diff --git a/docs/docs/reference/contextual/typeclasses.md b/docs/docs/reference/contextual/typeclasses.md index 06a39b30f7c7..a605bb72fd56 100644 --- a/docs/docs/reference/contextual/typeclasses.md +++ b/docs/docs/reference/contextual/typeclasses.md @@ -17,7 +17,7 @@ trait Monoid[T] extends SemiGroup[T] { def unit: T } object Monoid { - def apply[T](given Monoid[T]) = the[Monoid[T]] + def apply[T](given Monoid[T]) = summon[Monoid[T]] } given Monoid[String] {