Skip to content

Commit ca0725b

Browse files
oderskyallanrenucci
authored andcommitted
Add 0.5 docs (#3579)
- Update "changes to implicit resolution" docs section - Add doc for Dependent Function Types
1 parent e8a6378 commit ca0725b

File tree

3 files changed

+89
-1
lines changed

3 files changed

+89
-1
lines changed

docs/docs/reference/changed/implicit-resolution.md

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ affect implicits on the language level.
2929
/*!*/ def f(implicit x: y.type) // error `y.type` not allowed as type of implicit
3030

3131
3. Nesting is now taken into account for selecting an implicit.
32-
Consider for instance the following scenario
32+
Consider for instance the following scenario:
3333

3434
def f(implicit i: C) = {
3535
def g(implicit j: C) = {
@@ -41,4 +41,40 @@ affect implicits on the language level.
4141
more deeply than `i`. Previously, this would have resulted in an
4242
ambiguity error.
4343

44+
4. The treatment of ambiguity errors has changed. If an ambiguity is encountered
45+
in some recursive step of an implicit search, the ambiguity is propagated to the caller.
46+
Example: Say you have the following definitions:
47+
48+
class A
49+
class B extends C
50+
class C
51+
implicit def a1: A
52+
implicit def a2: A
53+
implicit def b(implicit a: A): B
54+
implicit def c: C
55+
56+
and the query `implicitly[C]`.
57+
58+
This query would now be classified as ambiguous. This makes sense, after all
59+
there are two possible solutions, `b(a1)` and `b(a2)`, neither of which is better
60+
than the other and both of which are better than the third solution, `c`.
61+
By contrast, Scala 2 would have rejected the search for `A` as
62+
ambiguous, and subsequently have classified the query `b(implicitly[A])` as a normal fail,
63+
which means that the alternative `c` would be chosen as solution!
64+
65+
Scala 2's somewhat puzzling behavior with respect to ambiguity has been exploited to implement
66+
the analogue of a "negated" search in implicit resolution, where a query `Q1` fails if some
67+
other query `Q2` succeeds and `Q1` succeeds if `Q2` fails. With the new cleaned up behavior
68+
these techniques no longer work. But there is now a new special type `scala.implicits.Not`
69+
which implements negation directly. For any query type `Q`: `Not[Q]` succeeds if and only if
70+
the implicit search for `Q` fails.
71+
72+
5. The treatment of divergence errors has also changed. A divergent implicit is
73+
treated as a normal failure, after which alternatives are still tried. This also makes
74+
sense: Encountering a divergent implicit means that we assume that no finite
75+
solution can be found on the given path, but another path can still be tried. By contrast
76+
most (but not all) divergence errors in Scala 2 would terminate the implicit
77+
search as a whole.
78+
79+
4480
[//]: # todo: expand with precise rules
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
---
2+
layout: doc-page
3+
title: "Dependent Function Types"
4+
---
5+
6+
A dependent function type describes functions where the result type may depend
7+
on the function's parameter values. Example:
8+
9+
class Entry { type Key; key: Key }
10+
11+
def extractKey(e: Entry): e.Key = e.key // a dependent method
12+
val extractor: (e: Entry) => e.Key = extractKey // a dependent function value
13+
14+
Scala already has _dependent methods_, i.e. methods where the result
15+
type refers to some of the parameters of the method. Method
16+
`extractKey` is an example. Its result type, `e.key` refers its
17+
parameter `e` (we also say, `e.Key` _depends_ on `e`). But so far it
18+
was not possible to turn such methods into function values, so that
19+
they can be passed as parameters to other functions, or returned as
20+
results. Dependent methods could not be turned into functions simply
21+
because there was no type that could describe them.
22+
23+
In Dotty this is now possible. The type of the `extractor` value above is
24+
25+
(e: Entry) => e.Key
26+
27+
This type describes function values that take any argument `x` of type
28+
`Entry` and return a result of type `x.Key`.
29+
30+
Recall that a normal function type `A => B` is represented as an
31+
instance of the `Function1` trait (i.e. `Function1[A, B]`) and
32+
analogously for functions with more parameters. Dependent functions
33+
are also represented as instances of these traits, but they get an additional
34+
refinement. In fact, the dependent function type above is just syntactic sugar for
35+
36+
Function1[Entry, Entry#Key] {
37+
def apply(e: Entry): e.Key
38+
}
39+
40+
In general, a dependent functon type `(x1: K1, ..., xN: KN) => R` of arity `N`
41+
translates to
42+
43+
FunctionN[K1, ..., Kn, R'] {
44+
def apply(x1: K1, ..., xN: KN): R
45+
}
46+
47+
where the result type parameter `R'` is an upper approximation of the
48+
true result type `R` that does not mention any of the parameters `e1, ..., eN`.
49+
50+

docs/sidebar.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ sidebar:
2525
url: docs/reference/type-lambdas.html
2626
- title: Implicit Function Types
2727
url: docs/reference/implicit-function-types.html
28+
- title: Dependent Function Types
29+
url: docs/reference/dependent-function-types.html
2830
- title: Phantom Types
2931
url: docs/reference/phantom-types.html
3032
- title: Literal Singleton Types

0 commit comments

Comments
 (0)