You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Have you ever wondered how this works---how you can pass a _method_ into `map`, which expects a _function_?
40
-
41
-
The technology behind this is known as _Eta Expansion_.
39
+
Why does this work? The process behind this is known as _eta-expansion_.
42
40
It converts an expression of _method type_ to an equivalent expression of _function type_, and it does so seamlessly and quietly.
43
41
44
42
## The differences between methods and functions
45
43
46
-
{% comment %}
47
-
NOTE: I got the following “method” definition from this page (https://dotty.epfl.ch/docs/reference/changed-features/eta-expansion-spec.html), but I’m not sure it’s 100% accurate now that methods can exist outside of classes/traits/objects.
48
-
I’ve made a few changes to that description that I hope are more accurate and up to date.
49
-
{% endcomment %}
50
-
51
-
Historically, _methods_ have been a part of the definition of a class, although in Scala 3 you can now have methods outside of classes, such as [Toplevel definitions][toplevel] and [extension methods][extension].
44
+
The key difference between methods and functions is that _a function is an object_, i.e. it is an instance of a class, and in turn has its own methods (e.g. try `f.apply` on a function `f`).
52
45
53
-
Unlike methods, _functions_ are complete objects themselves, making them first-class entities.
46
+
_Methods_ are not values that can be passed around, i.e. they can only be called via method application (e.g. `foo(arg1, arg2, ...)`). Methods can be _converted_ to a value by creating a function value that will call the method when supplied with the required arguments. This is known as eta-expansion.
54
47
55
-
Their syntax is also different.
56
-
This example shows how to define a method and a function that perform the same task, determining if the given integer is even:
48
+
More concretely: with automatic eta-expansion, the compiler automatically converts any _method reference_, without supplied arguments, to an equivalent _anonymous function_ that will call the method. For example, the reference to `times10` in the code above gets rewritten to `x => times10(x)`, as seen here:
57
49
58
-
{% tabs fun_3 %}
59
-
{% tab 'Scala 2 and 3' for=fun_3 %}
50
+
{% tabs fun_2_expanded %}
51
+
{% tab 'Scala 2 and 3' %}
60
52
61
53
```scala
62
-
defisEvenMethod(i: Int) = i %2==0// a method
63
-
valisEvenFunction= (i: Int) =>i %2==0//a function
54
+
deftimes10(i: Int) = i *10
55
+
List(1, 2, 3).map(x =>times10(x)) //eta expansion of `.map(times10)`
64
56
```
65
57
66
58
{% endtab %}
67
59
{% endtabs %}
68
60
69
-
The function truly is an object, so you can use it just like any other variable, such as putting it in a list:
61
+
> For the curious, the term eta-expansion has its origins in the [Lambda Calculus](https://en.wikipedia.org/wiki/Lambda_calculus).
62
+
63
+
## When does eta-expansion happen?
70
64
71
-
{% tabs fun_4 %}
72
-
{% tab 'Scala 2 and 3' for=fun_4 %}
65
+
Automatic eta-expansion is a desugaring that is context-dependent (i.e. the expansion conditionally activates, depending on the surrounding code of the method reference.)
66
+
67
+
{% tabs fun_5 class=tabs-scala-version %}
68
+
{% tab 'Scala 2' %}
73
69
70
+
In Scala 2 eta-expansion only occurs automatically when the expected type is a function type.
71
+
For example, the following will fail:
74
72
```scala
75
-
valfunctions=List(isEvenFunction)
73
+
defisLessThan(x: Int, y: Int):Boolean= x < y
74
+
75
+
valmethods=List(isLessThan)
76
+
// ^^^^^^^^^^
77
+
// error: missing argument list for method isLessThan
78
+
// Unapplied methods are only converted to functions when a function type is expected.
79
+
// You can make this conversion explicit by writing `isLessThan _` or `isLessThan(_,_)` instead of `isLessThan`.
76
80
```
77
81
82
+
See [below](#manual-eta-expansion) for how to solve this issue with manual eta-expansion.
78
83
{% endtab %}
79
-
{% endtabs %}
80
84
81
-
{% tabs fun_5 class=tabs-scala-version %}
82
-
{% tab 'Scala 2' for=fun_5 %}
85
+
{% tab 'Scala 3' %}
86
+
87
+
New to Scala 3, method references can be used everywhere as a value, they will be automatically converted to a function object with a matching type. e.g.
83
88
84
89
```scala
85
-
// this example shows the Scala 2 error message
86
-
valmethods=List(isEvenMethod)
87
-
^
88
-
error: missing argument list for method isEvenMethod
89
-
Unapplied methods are only converted to functions when a function typeis expected.
90
-
You can make this conversion explicit by writing `isEvenMethod _` or `isEvenMethod(_)` instead of `isEvenMethod`.
91
-
```
90
+
defisLessThan(x: Int, y: Int):Boolean= x < y
92
91
93
-
Conversely, a method technically isn’t an object, so in Scala 2 you couldn’t put a method in a `List`, at least not directly, as shown in this example:
92
+
valmethods=List(isLessThan) // works
93
+
```
94
94
95
95
{% endtab %}
96
+
{% endtabs %}
97
+
98
+
## Manual eta-expansion
96
99
97
-
{% tab 'Scala 3' for=fun_5 %}
100
+
You can always manually eta-expand a method to a function value, here are some examples how:
101
+
102
+
{% tabs fun_6 class=tabs-scala-version %}
103
+
{% tab 'Scala 2' %}
98
104
99
105
```scala
100
-
valfunctions=List(isEvenFunction) // works
101
-
valmethods=List(isEvenMethod) // works
106
+
valmethodsA=List(isLessThan _) // way 1: expand all parameters
107
+
valmethodsB=List(isLessThan(_, _)) // way 2: wildcard application
108
+
valmethodsC=List((x, y) => isLessThan(x, y)) // way 3: anonymous function
102
109
```
103
110
104
-
The important part for Scala 3 is that the Eta Expansion technology is improved, so now when you attempt to use a method as a variable, it just works---you don’t have to handle the manual conversion yourself.
111
+
{% endtab %}
112
+
113
+
{% tab 'Scala 3' %}
114
+
115
+
```scala
116
+
valmethodsA=List(isLessThan(_, _)) // way 1: wildcard application
117
+
valmethodsB=List((x, y) => isLessThan(x, y)) // way 2: anonymous function
118
+
```
105
119
106
120
{% endtab %}
107
121
{% endtabs %}
108
122
123
+
## Summary
124
+
109
125
For the purpose of this introductory book, the important things to know are:
110
126
111
-
-Eta Expansion is the Scala technology that lets you use methods just like functions
112
-
-The technology has been improved in Scala 3 to be almost completely seamless
127
+
-eta-expansion is a helpful desugaring that lets you use methods just like functions,
128
+
-the automatic eta-expansion been improved in Scala 3 to be almost completely seamless.
113
129
114
130
For more details on how this works, see the [Eta Expansion page][eta_expansion] in the Reference documentation.
0 commit comments