Skip to content

Commit 85efd24

Browse files
committed
Add reference docs
Add sections to reference that explain the new rules for eta expansion and auto-application.
1 parent 416d290 commit 85efd24

File tree

5 files changed

+140
-1
lines changed

5 files changed

+140
-1
lines changed

compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ object EtaExpansion {
7979
* val xN = argN
8080
* x0.f(x1, ..., xN)
8181
*
82-
* But leave idempotent expressions alone.
82+
* But leave pure expressions alone.
8383
*
8484
*/
8585
def liftApp(defs: mutable.ListBuffer[Tree], tree: Tree)(implicit ctx: Context): Tree = tree match {
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
---
2+
layout: doc-page
3+
title: "Automatic Eta Expansion"
4+
---
5+
6+
Previously, a method reference `m` was converted to a function value
7+
only if the expected type was a function type. If that was not the
8+
case, one had to write `m _` to force the conversion (which is called
9+
eta-expansion).
10+
11+
For methods with one or more parameters, this restriction has now been
12+
dropped. Example:
13+
14+
def m(x: Boolean, y: String)(z: Int): List[Int]
15+
val f1 = m
16+
val f2 = m(true, "abc")
17+
18+
This creates two function values:
19+
20+
f1: (Boolean, String) => Int => List[Int]
21+
f2: Int => List[Int]
22+
23+
The syntax `m _` is no longer needed and will be deprecated in the
24+
future.
25+
26+
Automatic eta expansion does not apply to "nullary" methods that take an empty parameter list. Given
27+
28+
def next(): T
29+
30+
, a simple reference to `next` does not auto-convert to a
31+
function. One has to write explicitely `() => next()` to achieve that
32+
(it's better to write it this way rather than `next _` because the latter
33+
will be deprecated).
34+
35+
The reason for excluding nullary methods from automatic eta expansion
36+
is that Scala implicitly inserts the `()` argument, which would
37+
conflict with eta expansion. Automatic `()` insertion is
38+
[limited](auto-apply.md) in Dotty, but the fundamental ambiguity
39+
remains.
40+
41+
### Reference
42+
43+
For more info, see [PR #2701](https://github.com/lampepfl/dotty/pull/2701).
44+
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
---
2+
layout: doc-page
3+
title: "Auto-Application"
4+
---
5+
6+
Previously an empty argument list `()` was implicitly inserted when
7+
calling a nullary method without arguments. E.g.
8+
9+
def next(): T = ...
10+
next // is expanded to next()
11+
12+
In Dotty, this idiom is an error.
13+
14+
next
15+
^
16+
missing arguments for method next
17+
18+
In Dotty, the application syntax has to follow exactly the parameter
19+
syntax. Excluded from this rule are methods that are defined in Java
20+
or that override methods defined in Java. The reason for being more
21+
lenient with such methods is that otherwise everyone would have to
22+
write
23+
24+
xs.toString().length()
25+
26+
instead of
27+
28+
xs.toString.length
29+
30+
The latter is idiomatic Scala because it conforms to the _uniform
31+
access principle_. This principle states that one should be able to
32+
change an object member from a field to a non-side-effecting method
33+
and back without affecting clients that access the
34+
member. Consequently, Scala encourages to define such "property"
35+
methods without a `()` parameter list whereas side-effecting methods
36+
should be defined with it. Methods defined in Java cannot make this
37+
distinction; for them a `()` is always mandatory. So Scala fixes the
38+
problem on the client side, by allowing the parameterless references.
39+
But where Scala allows that freedom for all method references, Dotty
40+
restricts it to references of external methods that are not defined
41+
themselves in Dotty.
42+
43+
For reasons of backwards compatibility, Dotty for the moment also
44+
auto-inserts `()` for nullary methods that are defined in Scala 2, or
45+
that override a method defined in Scala 2. It turns out that, because
46+
the correspondence between definition and call was not enforced in
47+
Scala so far, there are quite a few method definitions in Scala 2
48+
libraries that use `()` in an inconsistent way. For instance, we
49+
find in `scala.math.Numeric`
50+
51+
def toInt(): Int
52+
53+
whereas `toInt` is written without parameters everywhere
54+
else. Enforcing strict parameter correspondence for references to
55+
such methods would project the inconsistencies to client code, which
56+
is undesirable. So Dotty opts for more leniency when type-checking
57+
references to such methods until most core libraries in Scala 2 have
58+
been cleaned up.
59+
60+
Stricter conformance rules also apply to overriding of nullary
61+
methods. It is no longer allowed to override a parameterless method
62+
by a nullary method or _vice versa_. Instead, both methods must agree
63+
exactly in their parameter lists.
64+
65+
class A {
66+
def next(): Int
67+
}
68+
class B extends A {
69+
/*!*/ def next: Int // overriding error: incompatible type
70+
}
71+
72+
Methods overriding Java or Scala-2 methods are again exempted from this
73+
requirement.
74+
75+
### Migrating code
76+
77+
Existing Scala code with inconsistent parameters can still be compiled
78+
in Dotty under `-language:Scala2`. When paired with the `-rewrite`
79+
option, the code will be automatcally rewritten to conforrm to Dotty's
80+
stricter checking.
81+
82+
### Reference
83+
84+
For more info, see [Issue #2570](https://github.com/lampepfl/dotty/issue/2570) and [PR #2716](https://github.com/lampepfl/dotty/pull/2716).
85+
86+
87+

docs/sidebar.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ sidebar:
6969
url: docs/reference/changed/vararg-patterns.html
7070
- title: Pattern matching
7171
url: docs/reference/changed/pattern-matching.html
72+
- title: Eta Expansion
73+
url: docs/reference/changed/eta-expansion.html
7274
- title: Dropped Features
7375
subsection:
7476
- title: DelayedInit
@@ -89,6 +91,8 @@ sidebar:
8991
url: docs/reference/dropped/limit22.html
9092
- title: XML literals
9193
url: docs/reference/dropped/xml.html
94+
- title: Auto-Application
95+
url: docs/reference/dropped/auto-apply.html
9296
- title: Contributing
9397
subsection:
9498
- title: Getting Started

tests/neg/overrides.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ class A[T] {
4040

4141
def f(x: T)(y: T = x) = y
4242

43+
def next: T
44+
4345
}
4446

4547
class B extends A[Int] {
@@ -48,6 +50,8 @@ class B extends A[Int] {
4850

4951
f(2)()
5052

53+
def next(): Int // error: incompatible type
54+
5155
}
5256

5357
class X {

0 commit comments

Comments
 (0)