Reputation: 11
Lets say we have a function def fun(x: X): X => Y
and we pass this function as a parameter to another function using fun _
instead of just fun
. I understand that fun _
is actually a function value, while fun
refers to a function definition.
For example let:
val a = List(1,2,3,4)
def fun(x: Int) = {println(x); x + 1}
Then Running:
//This line works
a.map(fun _)
//This one also works, even though "fun" is not a function value
a.map(fun)
They have the same output:
1
2
3
4
resX: List[Int] = List(2, 3, 4, 5)
For the most part they seem to work the same, are there any examples in which the function value is not equivalent to the function definition?
Upvotes: 1
Views: 362
Reputation: 2128
In the signature of map
, you can see that it's expecting a
"function" to apply to each element
But in your code, fun
is a regular method in a class. So when you do:
a.map(fun _)
you are explicitly asking for eta-expansion. When you do:
a.map(fun)
you are implicitly asking for eta-expansion.
Because fun
is a "method", and is being used in a place where a Function
type is expected, it's automagically converted to that type. Basically to something like:
new Function1[Int, Int] {
def apply(x: Int): Int = fun(x)
}
This transformation converting the name fun
to a Function
is called eta-expansion
. See documentation for details.
Unfortunately, there are various ways of doing what you're doing - a.map(fun)
, a.map(fun _)
, a.map(fun(_))
and a.map(x => fun(x))
. This is one of those frequent scenarios in Scala where you can explicitly do something yourself, or explicitly ask the compiler to do it for you, or just let the compiler do it implicitly. They can have different behaviors because of implicits and it can be a major source of confusion. Also, _
is heavily overloaded in the language, only adding to the confusion. So I use implicit behavior sparingly in general.
Upvotes: 4
Reputation: 5572
As others have pointed out in the comments, you need to use the fun _
syntax (which performs an eta expansion) when you need a value (methods have no value by themselves). Within the context of a map (or other functional contexts) an eta expansion is performed on the method implicitly. There are some cases where the eta expansion must be triggered manually.
As a concrete example of where an explicit eta expansion is needed, consider this valid snippet:
def f1(x: Int): Int = 2*x
def f2(x: Int): Int = 3*x
val fList1 = List(f1 _, f2 _)
fList1.map(_(2)) // List(4, 6)
as opposed to this invalid snippet.
val fList2 = List(f1, f2)
Upvotes: 2