From 2fc1d6b7c6bd675c0fbff8542a6a8bde7c96a611 Mon Sep 17 00:00:00 2001 From: Olivier Blanvillain Date: Fri, 26 Oct 2018 17:17:16 +0200 Subject: [PATCH 1/4] Add more details page for implicit function types --- .../reference/implicit-function-types-spec.md | 88 +++++++++++++++++++ .../docs/reference/implicit-function-types.md | 2 + 2 files changed, 90 insertions(+) create mode 100644 docs/docs/reference/implicit-function-types-spec.md diff --git a/docs/docs/reference/implicit-function-types-spec.md b/docs/docs/reference/implicit-function-types-spec.md new file mode 100644 index 000000000000..cf2d0bd96db1 --- /dev/null +++ b/docs/docs/reference/implicit-function-types-spec.md @@ -0,0 +1,88 @@ +--- +layout: doc-page +title: "Implicit Function Types - More Details" +--- + +Initial implementation in (#1775)[https://github.com/lampepfl/dotty/pull/1775]. + +## Syntax + +Type ::= [`implicit'] FunArgTypes `=>' Type + | HkTypeParamClause `=>' Type + | InfixType +Expr ::= [`implicit'] FunParams `=>' Expr +BlockResult ::= [`implicit'] FunParams `=>' Block + | Expr1 + +Implicit function types associate to the right, e.g. +`implicit S ⇒ implicit T ⇒ U` is the same as `implicit S ⇒ (implicit T ⇒ U)`. + +## Implementation + +Implicit function types are shorthands for class types that define `apply` +methods with implicit parameters. Specifically, the `N`-ary function type +`implicit T1, ..., TN ⇒ R` is a shorthand for the class type +`ImplicitFunctionN[T1 , ... , TN, R]`. Such class types are defined in the +Scala library for `N` between 1 and 22 as follows. + + package scala + trait ImplicitFunctionN[-T1 , ... , -TN, +R] { + def apply(implicit x1: T1 , ... , xN: TN): R + } + +Anonymous implicit functions `implicit (x1: T1, ..., xn: Tn) => e` map +implicit parameters `xi` of types `Ti` to a result given by expression `e`. +The scope of each implicit parameter `xi` is `e`. Implicit parameters must +have pairwise distinct names. + +If the expected type of the anonymous implicit function is of the form +`scala.ImplicitFunctionN[S1, ..., Sn, R]`, the expected type of `e` is `R` and +the type `Ti` of any of the parameters `xi` can be omitted, in which case `Ti += Si` is assumed. If the expected type of the anonymous implicit function is +some other type, all implicit parameter types must be explicitly given, and +the expected type of `e` is undefined. The type of the anonymous implicit +function is `scala.ImplicitFunctionN[S1, ...,Sn, T]`, where `T` is the packed +type of `e`. `T` must be equivalent to a type which does not refer to any of +the implicit parameters `xi`. + +The anonymous implicit function is evaluated as the instance creation +expression: + + new scala.ImplicitFunctionN[T1, ..., Tn, T] { + def apply(implicit x1: T1, ..., xn: Tn): T = e + } + +In the case of a single untyped implicit parameter, `implicit (x) => e` can be +abbreviated to `implicit x => e`. If an anonymous implicit function `implicit +(x: T) => e` with a single typed parameter appears as the result expression of +a block, it can be abbreviated to `implicit x: T => e` + +A implicit parameter may also be a wildcard represented by an underscore `_`. In +that case, a fresh name for the parameter is chosen arbitrarily. + +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 the Scala 2.12 is subsumed by implicit function types and should +be remove. + +Anonymous implicit functions `implicit (x1: T1, ..., xn: Tn) => e` are +automatically inserted around any expression `e` whose expected type is +`scala.ImplicitFunctionN[T1, ..., Tn, R]`. This is analogous to the automatic +insertion of `scala.Function0` around expression in by-name argument position. + +Implicit functions generalize to `N > 22` in the same way that functions do, +see [the corresponding +documentation](https://dotty.epfl.ch/docs/reference/dropped/limit22.html). + +## Examples + +See the section on Expressiveness from [Simplicitly: foundations and +applications of implicit function +types](https://dl.acm.org/citation.cfm?id=3158130). I've extracted it in [this +Gist](https://gist.github.com/OlivierBlanvillain/234d3927fe9e9c6fba074b53a7bd9 +592), it might easier to access than the pdf. + +### Type Checking + +After desugaring no additional typing rules are required for implicit function +types. diff --git a/docs/docs/reference/implicit-function-types.md b/docs/docs/reference/implicit-function-types.md index 6570aeb929c7..e3b956ecbf46 100644 --- a/docs/docs/reference/implicit-function-types.md +++ b/docs/docs/reference/implicit-function-types.md @@ -101,3 +101,5 @@ With that setup, the table construction code above compiles and expands to: ### Reference For more info, see the [blog article](https://www.scala-lang.org/blog/2016/12/07/implicit-function-types.html). + +[More details](./implicit-function-types-spec.html) From 8b4f0fa21ed6ee85e103e49af8a21da224e713ec Mon Sep 17 00:00:00 2001 From: Olivier Blanvillain Date: Fri, 26 Oct 2018 17:26:16 +0200 Subject: [PATCH 2/4] Add more details page for dependent function types --- .../dependent-function-types-spec.md | 48 +++++++++++++++++++ .../reference/dependent-function-types.md | 18 ++----- 2 files changed, 52 insertions(+), 14 deletions(-) create mode 100644 docs/docs/reference/dependent-function-types-spec.md diff --git a/docs/docs/reference/dependent-function-types-spec.md b/docs/docs/reference/dependent-function-types-spec.md new file mode 100644 index 000000000000..c6f33e9cb705 --- /dev/null +++ b/docs/docs/reference/dependent-function-types-spec.md @@ -0,0 +1,48 @@ +--- +layout: doc-page +title: "Dependent Function Types - More Details" +--- + +Initial implementation in (#3464)[https://github.com/lampepfl/dotty/pull/3464]. + +## Syntax + +FunArgTypes ::= InfixType + | ‘(’ [ FunArgType {‘,’ FunArgType } ] ‘)’ + | '(' TypedFunParam {',' TypedFunParam } ')' +TypedFunParam ::= id ':' Type + +Dependent function types associate to the right, e.g. +`(s: S) ⇒ (t: T) ⇒ U` is the same as `(s: S) ⇒ ((t: T) ⇒ U)`. + +## Implementation + +Dependent function types are shorthands for class types that define `apply` +methods with a dependent result type.Dependent function types desugar to +refinement types of `scala.FunctionN`. A dependent functon type +`(x1: K1, ..., xN: KN) => R` of arity `N` translates to + + FunctionN[K1, ..., Kn, R'] { + def apply(x1: K1, ..., xN: KN): R + } + +where the result type parameter `R'` is the least upper approximation of the +precise result type `R` without any referance to value parameters `x1, ..., xN`. + +The syntax and sementics of anonymous dependent functions is identical to the +one of regular functions. Eta expansion is naturaly generalized to produce +dependent function types for methods with dependent result types. + +Dependent functions can be implicit, and generalize to arity `N > 22` in the +same way that other functions do, see [the corresponding +documentation](https://dotty.epfl.ch/docs/reference/dropped/limit22.html). + +## Examples + +- (depfuntype.scala)[https://github.com/lampepfl/dotty/blob/0.10.x/tests/pos/depfuntype.scala] + +- (eff-dependent.scala)[https://github.com/lampepfl/dotty/blob/0.10.x/tests/run/eff-dependent.scala] + +### Type Checking + +After desugaring no additional typing rules are required for dependent function types. diff --git a/docs/docs/reference/dependent-function-types.md b/docs/docs/reference/dependent-function-types.md index 47530e1c5006..efd8f19f02c7 100644 --- a/docs/docs/reference/dependent-function-types.md +++ b/docs/docs/reference/dependent-function-types.md @@ -10,9 +10,9 @@ on the function's parameter values. Example: def extractKey(e: Entry): e.Key = e.key // a dependent method val extractor: (e: Entry) => e.Key = extractKey // a dependent function value - // ║ ⇓ ⇓ ⇓ ⇓ ⇓ ⇓ ⇓ ║ - // ║ Dependent ║ - // ║ Function Type ║ + // ║ ⇓ ⇓ ⇓ ⇓ ⇓ ⇓ ⇓ ║ + // ║ Dependent ║ + // ║ Function Type ║ // ╚═══════════════════╝ Scala already has _dependent methods_, i.e. methods where the result type refers to some of the parameters of the method. Method @@ -40,14 +40,4 @@ refinement. In fact, the dependent function type above is just syntactic sugar f def apply(e: Entry): e.Key } -In general, a dependent functon type `(x1: K1, ..., xN: KN) => R` of arity `N` -translates to - - FunctionN[K1, ..., Kn, R'] { - def apply(x1: K1, ..., xN: KN): R - } - -where the result type parameter `R'` is an upper approximation of the -true result type `R` that does not mention any of the parameters `x1, ..., xN`. - - +[More details](./dependent-function-types-spec.html) From 10ae0c3b3b9e97f91b73b7ee734e60ec446b5a3f Mon Sep 17 00:00:00 2001 From: Olivier Blanvillain Date: Fri, 26 Oct 2018 18:44:56 +0200 Subject: [PATCH 3/4] Add more details page on Class Shadowing --- .../reference/dropped/class-shadowing-spec.md | 25 +++++++++++++++++++ .../docs/reference/dropped/class-shadowing.md | 4 +-- 2 files changed, 26 insertions(+), 3 deletions(-) create mode 100644 docs/docs/reference/dropped/class-shadowing-spec.md diff --git a/docs/docs/reference/dropped/class-shadowing-spec.md b/docs/docs/reference/dropped/class-shadowing-spec.md new file mode 100644 index 000000000000..42e90bd38889 --- /dev/null +++ b/docs/docs/reference/dropped/class-shadowing-spec.md @@ -0,0 +1,25 @@ +--- +layout: doc-page +title: "Dropped: Class Shadowing - More Details" +--- + +Spec diff: in section [5.1.4 Overriding](https://www.scala-lang.org/files/archive/spec/2.12/05-classes-and-objects.html), add *M' must not be a class*. + +> Why do we want to make this change to the language? + +tbd + + +> How much existing code is going to be affected? + +From all the code compiled so far with Dotty the only instance of this I could find is in the stdlib. Looking at [this commit](https://github.com/lampepfl/scala/commit/68f13bf39979b631ed211ec1751934306ceb5d6c#diff-7aa508b70e055b47c823764e3e5646b8) it seems like the usage of class shadowing was accidental. + + +> How exactly is existing code going to be affected? + +Code that relies on overridden inner classes will stop compiling. + + +> Is this change going to be migratable automatically? + +No. diff --git a/docs/docs/reference/dropped/class-shadowing.md b/docs/docs/reference/dropped/class-shadowing.md index b850f5fab846..f9df14a7b028 100644 --- a/docs/docs/reference/dropped/class-shadowing.md +++ b/docs/docs/reference/dropped/class-shadowing.md @@ -24,6 +24,4 @@ other, but classes in Scala cannot be overridden. To keep things clean (and its internal operations consistent) the Dotty compiler forces you to rename the inner classes so that their names are different. - - - +[More details](./class-shadowing-spec.html) From 1d07a22c53eb79701494f09bb5e749d59bca7771 Mon Sep 17 00:00:00 2001 From: Olivier Blanvillain Date: Thu, 1 Nov 2018 14:59:52 +0100 Subject: [PATCH 4/4] Address review --- .../reference/dependent-function-types-spec.md | 8 ++++---- .../reference/dropped/class-shadowing-spec.md | 2 +- .../reference/implicit-function-types-spec.md | 16 ++++++++-------- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/docs/docs/reference/dependent-function-types-spec.md b/docs/docs/reference/dependent-function-types-spec.md index c6f33e9cb705..1d7cc23414f3 100644 --- a/docs/docs/reference/dependent-function-types-spec.md +++ b/docs/docs/reference/dependent-function-types-spec.md @@ -7,10 +7,10 @@ Initial implementation in (#3464)[https://github.com/lampepfl/dotty/pull/3464]. ## Syntax -FunArgTypes ::= InfixType - | ‘(’ [ FunArgType {‘,’ FunArgType } ] ‘)’ - | '(' TypedFunParam {',' TypedFunParam } ')' -TypedFunParam ::= id ':' Type + FunArgTypes ::= InfixType + | ‘(’ [ FunArgType {‘,’ FunArgType } ] ‘)’ + | '(' TypedFunParam {',' TypedFunParam } ')' + TypedFunParam ::= id ':' Type Dependent function types associate to the right, e.g. `(s: S) ⇒ (t: T) ⇒ U` is the same as `(s: S) ⇒ ((t: T) ⇒ U)`. diff --git a/docs/docs/reference/dropped/class-shadowing-spec.md b/docs/docs/reference/dropped/class-shadowing-spec.md index 42e90bd38889..84e4cfdba9ce 100644 --- a/docs/docs/reference/dropped/class-shadowing-spec.md +++ b/docs/docs/reference/dropped/class-shadowing-spec.md @@ -7,7 +7,7 @@ Spec diff: in section [5.1.4 Overriding](https://www.scala-lang.org/files/archiv > Why do we want to make this change to the language? -tbd +Class shadowing is irregular compared to other types of overrides. Indeed, inner classes are not actually overriden but simply shadowed. > How much existing code is going to be affected? diff --git a/docs/docs/reference/implicit-function-types-spec.md b/docs/docs/reference/implicit-function-types-spec.md index cf2d0bd96db1..0453bcdf1a0c 100644 --- a/docs/docs/reference/implicit-function-types-spec.md +++ b/docs/docs/reference/implicit-function-types-spec.md @@ -7,12 +7,12 @@ Initial implementation in (#1775)[https://github.com/lampepfl/dotty/pull/1775]. ## Syntax -Type ::= [`implicit'] FunArgTypes `=>' Type - | HkTypeParamClause `=>' Type - | InfixType -Expr ::= [`implicit'] FunParams `=>' Expr -BlockResult ::= [`implicit'] FunParams `=>' Block - | Expr1 + Type ::= [`implicit'] FunArgTypes `=>' Type + | HkTypeParamClause `=>' Type + | InfixType + Expr ::= [`implicit'] FunParams `=>' Expr + BlockResult ::= [`implicit'] FunParams `=>' Block + | Expr1 Implicit function types associate to the right, e.g. `implicit S ⇒ implicit T ⇒ U` is the same as `implicit S ⇒ (implicit T ⇒ U)`. @@ -41,7 +41,7 @@ the type `Ti` of any of the parameters `xi` can be omitted, in which case `Ti = Si` is assumed. If the expected type of the anonymous implicit function is some other type, all implicit parameter types must be explicitly given, and the expected type of `e` is undefined. The type of the anonymous implicit -function is `scala.ImplicitFunctionN[S1, ...,Sn, T]`, where `T` is the packed +function is `scala.ImplicitFunctionN[S1, ...,Sn, T]`, where `T` is the widened type of `e`. `T` must be equivalent to a type which does not refer to any of the implicit parameters `xi`. @@ -63,7 +63,7 @@ that case, a fresh name for the parameter is chosen arbitrarily. 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 the Scala 2.12 is subsumed by implicit function types and should -be remove. +be removed. Anonymous implicit functions `implicit (x1: T1, ..., xn: Tn) => e` are automatically inserted around any expression `e` whose expected type is