7

I can define the following two functions:

def add(a: Int, b: Int, c: Int) = a + b + c

this results in

add: (a: Int, b: Int, c: Int)Int

and

val add2 = (a: Int, b: Int, c: Int) => a + b + c

this results in

add2: (Int, Int, Int) => Int = <function3>

Both of these are functions that do the exact same thing but defined in a different way, what I do not understand is if I go ahead and define a partially applied function as follows:

def a = add _

This results in

a: (Int, Int, Int) => Int = <function3> 

as expected, a function that takes 3 parameters and returns an Int, but if I do

def a2 = add2 _

This results in

a2: () => (Int, Int, Int) => Int = <function0>

which seems to be a function that takes no parameters and returns a function that takes 3 Int parameters and returns an Int. Why does this happen? Can someone please explain what is going on?

thanks

kgrad
  • 4,672
  • 7
  • 36
  • 57
  • possible duplicate of [Declaring functions two ways. What is the distinction?](http://stackoverflow.com/questions/2720486/declaring-functions-two-ways-what-is-the-distinction) – Daniel C. Sobral Mar 03 '12 at 14:04
  • That duplicate was the third related link. Really, do try to look for previously asked question -- this one has been asked many, many times. While I think that link is a closest duplicate, I personally recommend [this answer](http://stackoverflow.com/questions/2529184/difference-between-method-and-function-in-scala/2530007#2530007) of mine to get to the bottom of the subject. – Daniel C. Sobral Mar 03 '12 at 14:05
  • Oh, by the way, perhaps you'll be clearer if you write `def add2` instead of `val add2`. – Daniel C. Sobral Mar 03 '12 at 14:07
  • Just noticed from a deleted answer you originally wrote `def` instead of `val`. Well, the difference between `def` and `val` is that the former computes the value every time it is called, while the latter computes it once and returns the pre-computed value when called. – Daniel C. Sobral Mar 03 '12 at 14:10

3 Answers3

9

This is a strange side-effect of Scala not actually having (user-accessible) fields, but instead having accessors (getters) for everything. Observe:

scala> val i = 1
i: Int = 1

scala> i _
res0: () => Int = <function0>

The reason is that i is actually an accessor (def i: Int) to an underlying (hidden, inaccessible) field. Since it's just a method, _ will convert it into a function. The accessor doesn't take any arguments, which is why you have a function that takes no parameters.

Rex Kerr
  • 166,841
  • 26
  • 322
  • 407
3

Scala has both functions and methods, they are not quite the same thing.

def add(a: Int, b: Int, c: Int) = a + b + c

Which defined a method (not a function!!).

val add2 = (a: Int, b: Int, c: Int) => a + b + c

Which assigned add2 a function value(not a method!!).

A method can’t be the final value, while a function can:

scala> add
<console>:9: error: missing arguments for method add;
follow this method with `_' if you want to treat it as a partially applied function
              add
              ^

scala> add2
res1: (Int, Int, Int) => Int = <function3>

scala> val a = add
<console>:8: error: missing arguments for method add;
follow this method with `_' if you want to treat it as a partially applied function
       val a = add
               ^

scala> val a2 = add2
a2: (Int, Int, Int) => Int = <function3>

Writing an underscore after the method name can explicitly convert a method into a function:

scala> add _
res2: (Int, Int, Int) => Int = <function3>

But if you writing an underscore after a value, it will convert to a function which take no argument with return type of its type:

scala> val s = ""
s: String = ""

scala> val i = 1
i: Int = 1

scala> s _
res3: () => String = <function0>

scala> i _
res4: () => Int = <function0>

So if the value itself is a function, writing an underscore after it will get a new function which take no argument with return type of function:

scala> add2 _
res5: () => (Int, Int, Int) => Int = <function0>
Eastsun
  • 18,526
  • 6
  • 57
  • 81
1

Effect is clearly described in Rex Kerr's answer but you should note that add2 is value already representing partially applied function, e.g. delegate. For demonstrating you could compare types of add1 _ expression and add2 value.

scala> def getManifest[T](x:T)(implicit m:scala.reflect.Manifest[T]) = m
getManifest: [T](x: T)(implicit m: scala.reflect.Manifest[T])scala.reflect.Manifest[T]

scala> getManifest(add1 _) == getManifest(add2)
res14: Boolean = true
Community
  • 1
  • 1
Odomontois
  • 15,918
  • 2
  • 36
  • 71