45

Here is a little Scala session that defines and tries out some functions:

scala> def test1(str: String) = str + str;    
test1: (str: String)java.lang.String

scala> test1("ab")
res0: java.lang.String = abab

works nicely.

scala> val test2 = test1
<console>:6: error: missing arguments for method test1 in object $iw;
follow this method with `_' if you want to treat it as a partially applied function
       val test2 = test1
                   ^

oops.

scala> val test2 = test1 _
test2: (String) => java.lang.String = <function1>

scala> test2("ab")
res1: java.lang.String = abab

works well!

Now, I've seen the _ syntax when folding (_ + _, etc). So as I understand it _ basically means "an argument". So test1 _ basically means a function with an argument, which is given to test1". But why isn't that exactly the same as just test1? Why is there a difference if I append a _?

So I kept exploring...

scala> val test3 = (str: String) => str + str
test3: (String) => java.lang.String = <function1>

scala> test3("ab")
res2: java.lang.String = abab

scala> val test4 = test3
test4: (String) => java.lang.String = <function1>

Here it works without _! What's the difference between a defed function, and a valed function?

tenshi
  • 26,268
  • 8
  • 76
  • 90
aioobe
  • 413,195
  • 112
  • 811
  • 826
  • 9
    Rex, I'm going to save you some time. You already answered this on the mailing list on 1/27/2010. It was a good response so I bookmarked it. http://scala-programming-language.1934581.n4.nabble.com/val-def-function-method-tp1956948p1956955.html – Bradford Feb 15 '11 at 21:13
  • 3
    I think there is some unfortunate confusion regarding the usage of the term "function" / "defining a function" in Scala. Even *Programming in Scala* says that `def` defines a function, but that's not quite true depending on your definition of "function". I.e. a method returns a result that is a *function of* its parameters, but the method is not a *function value* or *function object*. It would probably be helpful to differentiate between these two usages of the term "function". – Knut Arne Vedaa Feb 15 '11 at 22:31
  • Read retronyms answer in my similar question from April '10. http://stackoverflow.com/questions/2720486/declaring-functions-two-ways-what-is-the-distinction - (ps, I QRd your avatar, very funny!) – Synesso Feb 15 '11 at 22:41
  • In short - function vs. method – Maxim Oct 14 '14 at 20:48
  • possible duplicate of [Functions vs methods in Scala](http://stackoverflow.com/questions/4839537/functions-vs-methods-in-scala) – earldouglas Jul 10 '15 at 14:09

3 Answers3

59

The def declares a method within a surrounding object/class/trait, similar to the way you define methods in Java. You can only use defs within other objects/classes/traits. In the REPL, you cannot see the surrounding object because it's "hidden", but it does exist.

You cannot assign a def to a value, because the def is not a value - it's a method in the object.

The (x: T) => x * x declares and instantiates a function object, which exists at runtime. Function objects are instances of anonymous classes which extend FunctionN traits. FunctionN traits come with an apply method. The name apply is special, because it can be omitted. Expression f(x) is desugared into f.apply(x).

The bottomline is - since function objects are runtime values which exist on the heap, you can assign them to values, variables and parameters, or return them from methods as return values.

To solve the issue of assigning methods to values (which can be useful), Scala allows you to use the placeholder character to create a function object from a method. Expression test1 _ in your example above actually creates a wrapper function around the method test1 - it is equivalent to x => test1(x).

axel22
  • 32,045
  • 9
  • 125
  • 137
54

There's no difference between a def'ed function and a val'ed function:

scala> def test1 = (str: String) => str + str
test1: (String) => java.lang.String

scala> val test2 = test1
test2: (String) => java.lang.String = <function1>

scala> val test3 = (str: String) => str + str
test3: (String) => java.lang.String = <function1>

scala> val test4 = test2
test4: (String) => java.lang.String = <function1>

See? All of these are functions, which is indicated by the X => Y type they have.

scala> def test5(str: String) = str + str
test5: (str: String)java.lang.String

Do you see an X => Y type? If you do, go see an ophthalmologist, because there's none. The type here is (X)Y, commonly used to denote a method.

Actually, test1, test2, test3 and test4 are all methods, which return functions. test5 is a method which returns a java.lang.String. Also, test1 through test4 do not take parameters (only test1 could, anyway), while test5 does.

So, the difference is pretty simple. In the first case, you tried to assign a method to a val, but did not fill in the parameters the method take. So it failed, until you added a trailing underscore, which meant turn my method into a function.

In the second example you had a function, so you didn't need to do anything else.

A method is not a function, and vice versa. A function is an object of one of the FunctionN classes. A method is a handle to some piece of code associated with an object.

See various questions about methods vs functions on Stack Overflow.

Saurabh
  • 71,488
  • 40
  • 181
  • 244
Daniel C. Sobral
  • 295,120
  • 86
  • 501
  • 681
  • I love this answer. Some follow-up questions: **1)** *Do you see an X => Y type?* How about the second line? Is it not `X => Y` because it has `(` and `)` around `String`? (Otherwise I'd have to look for an oftamologist in the yellow-pages.) **2)** From your description it seems to me that functions are strictly more general than methods, and that I could use your `test1`-notation instead of `test5`-notation everywhere? What would the drawback be? – aioobe Feb 16 '11 at 08:15
  • @Synesso Yes, no, kind of. It's REPL's representation of an hypothetical method type. – Daniel C. Sobral Feb 16 '11 at 16:06
  • 1
    @aioobe The second line is not `X => Y` because there's no `=>`. Functions are slower than methods, and they cannot receive type parameters -- this has been discussed elsewhere on Stack Overflow. – Daniel C. Sobral Feb 16 '11 at 16:08
  • ```scala> val test4 = test2``` is it volunteer, or you meant val ```test4 = test3```? – DenisFLASH Mar 11 '18 at 10:33
11

The underscore means different things in different contexts. But it can always be thought of as the thing that would go here, but doesn't need to be named.

When applied in place of parameters, the effect is to lift the method to a function.

scala> def test1(str: String) = str + str; 
test1: (str: String)java.lang.String

scala> val f1 = test1 _
f1: (String) => java.lang.String = <function1>

Note, the method has become a function of type (String) => String.

The distinction between a method and a function in Scala is that methods are akin to traditional Java methods. You can't pass them around as values. However functions are values in their own right and can be used as input parameters and return values.

The lifting can go further:

scala> val f2 = f1 _
f2: () => (String) => java.lang.String = <function0>

Lifting this function results in another function. This time of type () => (String) => (String)

From what I can tell, this syntax is equivalent to substituting all of the parameters with an underscore explicitly. For example:

scala> def add(i: Int, j: Int) = i + j
add: (i: Int,j: Int)Int

scala> val addF = add(_, _)
addF: (Int, Int) => Int = <function2>

scala> val addF2 = add _    
addF2: (Int, Int) => Int = <function2>
Synesso
  • 37,610
  • 35
  • 136
  • 207