开发者

What's the fundamental difference between those two constructs? [duplicate]

开发者 https://www.devze.com 2023-04-07 19:08 出处:网络
This question already has answers here: Closed 11 years ago. Possible Duplicate: Differ开发者_运维问答ence between method and function in Scala
This question already has answers here: Closed 11 years ago.

Possible Duplicate:

Differ开发者_运维问答ence 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 ?


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
    */
}
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号