Skip to content

Commit 11dae6f

Browse files
committed
Update automatic eta-expansion spec
1 parent 4100f88 commit 11dae6f

File tree

2 files changed

+116
-34
lines changed

2 files changed

+116
-34
lines changed
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
---
2+
layout: doc-page
3+
title: "Automatic Eta Expansion"
4+
---
5+
6+
### Motivation
7+
8+
Scala maintains a convenient distinction between _methods_ and _functions_.
9+
Methods are part of the definition of a class that can be invoked in objects while functions are complete objects themselves, making them first-class entities. For example they can be assigned in variables.
10+
These two mechanisms are bridged in Scala by a mechanism called _eta-expansion_ in literature also called eta-abstraction).
11+
According to this, methods can be turned into functions.
12+
The intuition behind this, is that if we have a function `f(x)` and we need to pass it around
13+
we can either pass its name `f` or a function `x => f(x)` which expresses the idea that two functions
14+
are equivalent if and only if they give the same result for all arguments.
15+
16+
Consequently, the essense of eta-expansion is captured in the following snippet.
17+
Imagine that the `val` is generated by the compiler, when the programmer writes ```f = m```.
18+
The right-hand side is not a function so the compiler performs _automatic eta-expansion_:
19+
20+
```scala
21+
def m(x: Int, y: String) = ???
22+
val f = m // generates val f = (x: Int, y: String) => m(x, y)
23+
```
24+
25+
In Scala, previously, a method reference `m` was converted to a function value
26+
only if the expected type was a function type. If that was not the
27+
case, one had to write `m _` to force the conversion.
28+
29+
For methods with one or more parameters like in the example above, this restriction has now been
30+
dropped. The syntax `m _` is no longer needed and will be deprecated in the
31+
future.
32+
33+
## Automatic eta-expansion and partial application
34+
In the following example `m` can be partially applied to the first two parameters.
35+
Assignining `m` to `f1` will automatically eta-expand.
36+
37+
```scala
38+
def m(x: Boolean, y: String)(z: Int): List[Int]
39+
val f1 = m
40+
val f2 = m(true, "abc")
41+
```
42+
43+
This creates two function values:
44+
45+
```scala
46+
f1: (Boolean, String) => Int => List[Int]
47+
f2: Int => List[Int]
48+
```
49+
50+
## Automatic eta-expansion and nullary methods
51+
52+
Automatic eta expansion does not apply to "nullary" methods that take an empty parameter list. Given
53+
54+
```scala
55+
def next(): T
56+
```
57+
58+
A simple reference to `next` does not auto-convert to a function.
59+
One has to write explicitly `() => next()` to achieve that
60+
Once again since the `_` is going to be deprecated it's better to write it this way
61+
rather than `next _`.
62+
63+
The reason for excluding nullary methods from automatic eta expansion
64+
is that Scala implicitly inserts the `()` argument, which would
65+
conflict with eta expansion. Automatic `()` insertion is
66+
[limited](../dropped/auto-apply.md) in Dotty, but the fundamental ambiguity
67+
remains.
68+
69+
## Automatic eta-expansion and implicit parameter lists
70+
71+
Methods with implicit parameter lists will always get applied to implicit arguments.
72+
73+
```scala
74+
def foo(x: Int)(implicit p: Double): Float = ???
75+
implicit val bla: Double = 1.0
76+
77+
val bar = foo // val bar: Int => Float = ...
78+
```
79+
80+
## Automatic Eta-Expansion and implicit function types
81+
82+
Methods with implicit parameter lists can be assigned to a value with an implicit function type
83+
only by using the expected type explicitly.
84+
85+
```scala
86+
def foo(x: Int)(implicit p: Double): Float = ???
87+
val bar: implicit Double => Float = foo(3) // val bar: implicit Double => Float = ...
88+
```
89+
90+
## Rules
91+
92+
- If `m` has one or more parameters, we always eta-expand
93+
- If `m` is nullary (i.e. has type `()R`):
94+
1. If the expected type is of the form `() => T`, we eta expand.
95+
2. If m is defined by Java, or overrides a Java defined method, we insert `()`.
96+
3. Otherwise we issue an error of the form:
97+
Unapplied nullary methods are only converted to functions when a function type is expected.
98+
You need to either apply the method to `()`, or convert it to a function with `() => m()`.
99+
100+
The syntax `m _` is deprecated.
101+
102+
### Reference
103+
104+
For more info, see [PR #2701](https://github.com/lampepfl/dotty/pull/2701).
105+

docs/docs/reference/changed/eta-expansion.md

Lines changed: 11 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -3,42 +3,19 @@ layout: doc-page
33
title: "Automatic Eta Expansion"
44
---
55

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).
6+
The conversion of _methods_ into _functions_ has been improved and happens automatically for methods with one or more parameters.
107

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")
8+
```scala
9+
def m(x: Boolean, y: String)(z: Int): List[Int]
10+
val f1 = m
11+
val f2 = m(true, "abc")
12+
```
1713

1814
This creates two function values:
15+
```scala
16+
f1: (Boolean, String) => Int => List[Int]
17+
f2: Int => List[Int]
18+
```
1919

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 explicitly `() => 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](../dropped/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).
20+
[More details](eta-expansion-spec.html)
4421

0 commit comments

Comments
 (0)