Pokemon master
Pokemon master

Reputation: 11

In Scala, what is the difference between fun _ and fun as parameters

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

Answers (2)

The_Tourist
The_Tourist

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

evan.oman
evan.oman

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

Related Questions