Skip to content

Add more detail pages for implicit/dependent functions and class Shadowing #5331

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Nov 3, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions docs/docs/reference/dependent-function-types-spec.md
Original file line number Diff line number Diff line change
@@ -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.
18 changes: 4 additions & 14 deletions docs/docs/reference/dependent-function-types.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
25 changes: 25 additions & 0 deletions docs/docs/reference/dropped/class-shadowing-spec.md
Original file line number Diff line number Diff line change
@@ -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?

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?

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.
4 changes: 1 addition & 3 deletions docs/docs/reference/dropped/class-shadowing.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
88 changes: 88 additions & 0 deletions docs/docs/reference/implicit-function-types-spec.md
Original file line number Diff line number Diff line change
@@ -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 widened
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 removed.

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.
2 changes: 2 additions & 0 deletions docs/docs/reference/implicit-function-types.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)