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/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 a3a3b12818bc..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] as Ord[List[T]] given (ord: Ord[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] as Ord[List[T]] given (ord: Ord[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] as Ord[List[T]] given Ord[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 as Context given (outer: 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,14 +78,12 @@ 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 ::= 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 47f8ef51c307..fc4506c4e526 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_. @@ -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]): 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] as Eq[T] given (m: Mirror.Of[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) @@ -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)) @@ -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]) = - eqSum(the[Mirror[Opt[T]]], +given derived$Eq[T](given eqT: Eq[T]): Eq[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) ) ) ``` @@ -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]): 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]): 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. @@ -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..1fe324dd5315 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 @@ -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 020fa95ef7e9..aa9c8b86ea33 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 : 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 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 `summon` 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 +summon[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 `summon` 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 summon[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..e98ad96fca8b 100644 --- a/docs/docs/reference/contextual/implicit-by-name-parameters.md +++ b/docs/docs/reference/contextual/implicit-by-name-parameters.md @@ -10,16 +10,16 @@ trait Codec[T] { def write(x: T): Unit } -given intCodec as Codec[Int] = ??? +given intCodec: Codec[Int] = ??? -given optionCodec[T] as Codec[Option[T]] given (ev: => Codec[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 => } } -val s = the[Codec[Option[Int]]] +val s = summon[Codec[Option[Int]]] s.write(Some(33)) s.write(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. @@ -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/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..63d8f764de20 100644 --- a/docs/docs/reference/contextual/implicit-function-types.md +++ b/docs/docs/reference/contextual/implicit-function-types.md @@ -7,23 +7,23 @@ _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: ```scala - given ec as ExecutionContext = ... + given ec: ExecutionContext = ... 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) = { - given t as Table + def table(init: (given Table) => Unit) = { + given t: Table init t } - def row(init: given Row => Unit) given (t: Table) = { - given r as Row + def row(init: (given Row) => Unit)(given t: Table) = { + given r: 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..ddf1bdaead61 100644 --- a/docs/docs/reference/contextual/import-delegate.md +++ b/docs/docs/reference/contextual/import-delegate.md @@ -1,29 +1,34 @@ --- 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 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._ - 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 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 @@ -34,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 given A.{_: 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 bounding with a union type. +is expressed by multiple `given` selectors. ``` -import given A.{_: T1 | ... | Tn} +import A.{given T1, ..., given 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 { - 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 given Instances.{_: Ordering[?] | 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 given Instances.{im, _: Ordering[?]} +import Instances.{im, given Ordering[?]} ``` would import `im`, `intOrd`, and `listOrd` but leave out `ec`. @@ -77,21 +82,35 @@ 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 - an old-style implicit definition can be brought into scope either by a normal import or by an import given. + 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 `_` 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. + +### Syntax + +``` +Import ::= ‘import’ ImportExpr {‘,’ ImportExpr} +ImportExpr ::= StableId ‘.’ ImportSpec +ImportSpec ::= id + | ‘_’ + | ‘given’ + | ‘{’ ImportSelectors) ‘}’ +ImportSelectors ::= id [‘=>’ id | ‘=>’ ‘_’] [‘,’ ImportSelectors] + | WildCardSelector {‘,’ WildCardSelector} +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 73d481399998..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] as Eql[Box[T], Box[U]] given Eql[T, 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 @@ -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..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] as Ord[List[T]] given (ord: Ord[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,13 +67,13 @@ 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 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. @@ -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 435320bbe4f0..a605bb72fd56 100644 --- a/docs/docs/reference/contextual/typeclasses.md +++ b/docs/docs/reference/contextual/typeclasses.md @@ -17,15 +17,15 @@ 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 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 =