4

Possible Duplicate:
Difference between method and function in Scala

scala> val x1 : (Int) => Int = (x) => x + 1
x1: (Int) => Int = <function>

scala> def x2 (x : Int) = x + 1
x2: (Int)Int

scala> x1(1)
res0: Int = 2

scala> x2(1)
res1: Int = 2

What's the actual difference between x1 and x2 . Can you please give me examples when to use those two constructs ?

Community
  • 1
  • 1
Andrei Ciobanu
  • 12,500
  • 24
  • 85
  • 118
  • 3
    [This question](http://stackoverflow.com/questions/2529184/difference-between-method-and-function-in-scala) and its answers pretty much cover everything. – Philippe Sep 27 '11 at 15:08
  • I think it really helps if you think of it as a method on an object, but I can also see why some people would disagree with that view. – Philippe Sep 27 '11 at 15:41
  • 1
    More on that: http://stackoverflow.com/questions/5009411/two-ways-of-defining-functions-in-scala-what-is-the-difference/ – axel22 Sep 27 '11 at 15:44
  • 1
    This question has been asked many times, but people never find the questions because they _don't know_ what the difference is, so they don't know how to ask. The first is a function, the second is a method. Knowing that, go read about the difference between them. – Daniel C. Sobral Sep 27 '11 at 23:28
  • 1
    @Jonas That's not correct. `x1` is a function, `x2` is a method. – Daniel C. Sobral Sep 27 '11 at 23:29

1 Answers1

2

In Scala, these are two construct that looks similar from user's perspective but totally different from JVM's perspective. x1 is a "function object" and x2 is a method.

Code Example

class Test
{
    val x1 = (x: Int) => x + 3
    def x2(x: Int) = {
        def x3(y: Int) = y + 10
        x3(x) + 3
    }
}

Method

In Scala, def defines a method that directly compile to a JVM method, and it must belong to some Java class.

In the above code snippet, both x2 and x3 are compiled to a JVM method, and belongs to the class Test, even x3 is defined inside a method (nested method).

You could verify this by using javap -private Test after compile the code. And it will output the following mesage:

brianhsu@USBGentoo ~/test $ javap -private Test
Compiled from "test.scala"
public class Test extends java.lang.Object implements scala.ScalaObject{
    private final scala.Function1 x1;
    public scala.Function1 x1();
    public int x2(int);
    private final int x3$1(int);
    public Test();
}

You could see that x2 is just an ordinary Java method, and x3 being renamed to x3$1 (to avoid name conflict if there is another x3 in other method`), but it still an normal Java method from JVM's point of view.

Function Object

I use this term to avoid confuse, this is what you defined with something like val x1 = (x: Int) => x + 1.

It may looks like method when you use it, but in fact it is totally different from the method you defined with defs.

Then what does val x1 = (x: Int) => x + 2 means?

Well, there is traits that called Function0, Function1, Function2, Function3...Function22 in Scala.

It both looks like the following (I've simplified it):

// T1 is the type of parameter 1, R is the type of return value
triat Function1[T1, R] {
    def apply(t1: T1): R
}

And when you write val x1 = (x: Int) => x + 2, the Scala compiler will generate an object that implements the trait Function1, and it may looks like the following:

val t = new Function1[Int, Int] { 
    def apply(t1: Int) = t1 + 2
}

And when you write x1(3), in fact the Scala is just convert it to t.apply(3).

So, an function object is not a method, it is just an ordinary Java object that has a method called apply, And the Scala compiler give you a syntax sugar that don't have to explicit call apply when you use them.

You could verify this by using javap again.

brianhsu@USBGentoo ~/test $ javap Test\$\$anonfun\$1 
Compiled from "test.scala" public final class Test$$anonfun$1 extends scala.runtime.AbstractFunction1$mcII$sp implements scala.Serializable{
    public static final long serialVersionUID;
    public static {};
    public final int apply(int);
    public int apply$mcII$sp(int);
    public final java.lang.Object apply(java.lang.Object);
    public Test$$anonfun$1(Test); 
}

brianhsu@USBGentoo ~/test $ javap -private Test 
Compiled from "test.scala" public class Test extends java.lang.Object implements scala.ScalaObject{
    private final scala.Function1 x1;
    public scala.Function1 x1();
    public int x2(int);
    private final int x3$1(int);
    public Test(); 
}

You will notice that there is an extra .class file called Test$$anonfun$1.class, that is the class of (x: Int) => x + 2, and you will notice there is an x1 private variable that is type of Function1 an a x1() method returns an scala.Function1.

There is x1() method because Scala implements Uniform Access Principle. But the under hood is that x1() method just return an function object instance of Test$$anonfun$1 class.

Conclusion

Maybe method and function looks same, but they are different things. Scala compiler help us to use them together without a lot of effort.

Most time you won't care about the difference between them, but indeed there are sometimes that something want an function object and you only have methods.

In this situation, the compiler will told you that add an _ after a method name to lift it to an function object.

Update

Here is an interesting code example that show the differences between method and function object: You could define a method take 25 parameters, but could not define an function object that takes more than 22 parameters.

class Test2
{
    def x (
      x01: Int, x02: Int, x03: Int, x04: Int, x05: Int,
      x06: Int, x07: Int, x08: Int, x09: Int, x10: Int,
      x11: Int, x12: Int, x13: Int, x14: Int, x15: Int,
      x16: Int, x17: Int, x18: Int, x19: Int, x20: Int,
      x21: Int, x22: Int, x23: Int, x24: Int, x25: Int
    ) = 0

    // Compile error: 
    //  implementation restricts functions to 22 parameters

    /*
    val y = (
      x01: Int, x02: Int, x03: Int, x04: Int, x05: Int,
      x06: Int, x07: Int, x08: Int, x09: Int, x10: Int,
      x11: Int, x12: Int, x13: Int, x14: Int, x15: Int,
      x16: Int, x17: Int, x18: Int, x19: Int, x20: Int,
      x21: Int, x22: Int, x23: Int, x24: Int, x25: Int
    ) => 0
    */
}
Brian Hsu
  • 8,781
  • 3
  • 47
  • 59