Scala maintains a convenient distinction between methods and functions. 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 to variables. These two mechanisms are bridged in Scala by a mechanism called eta-expansion (also called eta-abstraction), which converts a reference to a method into a function. Intuitively, a method m
can be passed around by turning it into an object: the function x => m(x)
.
In this snippet which assigns a method to a val
, the compiler will perform automatic eta-expansion, as shown in the comment:
def m(x: Int, y: String) = ???
val f = m // becomes: val f = (x: Int, y: String) => m(x, y)
In Scala 2, a method reference m
is converted to a function value only if the expected type is a function type, which means the conversion in the example above would not have been triggered, because val f
does not have a type ascription. To still get eta-expansion, a shortcut m _
would force the conversion.
For methods with one or more parameters like in the example above, this restriction has now been dropped. The syntax m _
is no longer needed and will be deprecated in the future.
In the following example m
can be partially applied to the first two parameters. Assigning m
to f1
will automatically eta-expand.
def m(x: Boolean, y: String)(z: Int): List[Int]
val f1 = m
val f2 = m(true, "abc")
This creates two function values:
f1: (Boolean, String) => Int => List[Int]
f2: Int => List[Int]
Automatic eta-expansion and implicit parameter lists
Methods with implicit parameter lists will always get applied to implicit arguments.
def foo(x: Int)(implicit p: Double): Float = ???
implicit val bla: Double = 1.0
val bar = foo // val bar: Int => Float = ...
Automatic Eta-Expansion and context types
A method with context parameters can be expanded to a value of a context type by writing the expected context type explicitly.
def foo(x: Int)(using p: Double): Float = ???
val bar: Double ?=> Float = foo(3)
Rules
m
has an argument list with one or more parameters, we always eta-expandm
is has an empty argument list (i.e. has type ()R
):
() => T
, we eta expand.()
.method must be called with () argument
Thus, an unapplied method with an empty argument list is only converted to a function when a function type is expected. It is considered best practice to either explicitly apply the method to ()
, or convert it to a function with () => m()
.
The method value syntax m _
is deprecated.
For more information, see PR #2701.
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4