宇宙人
宇宙人

Reputation: 1227

define function in scala, difference between FunctionName and FunctionName(_)

I try to define a recursive function in Scala with following code:

object Factorial {
    val almostFactorial = (f: Int => Int) => (n: Int) => if(n == 0) 1 else n * f(n - 1)
    val factorial: Int => Int = almostFactorial(factorial)
    def main(args: Array[String]) {
        println(factorial(5))
    }
}

The above code compiles but runs with exception:

Exception in thread "main" java.lang.NullPointerException

But if I change

val factorial: Int => Int = almostFactorial(factorial)

into

val factorial: Int => Int = almostFactorial(factorial(_))

Then it runs well.

What's the difference between these two declaration, and why does the first one cause that exception?

Upvotes: 3

Views: 91

Answers (2)

Andreas Neumann
Andreas Neumann

Reputation: 10894

1. implementation: Why this causes a null Pointer Exception

val factorial: Int => Int = {
  println(s"Before recursive def: $factorial")
  almostFactorial(factorial)
}

Running this code shows you that in the recursive definition factorial is null. The answer lies in the implementation of Scala Function values as objects in the JVM. As the default value for objects is null and factorial is not yet initialised when assigned to val factorial : Int => Int is null.

As the object is created vals are instantly evaluated. So the compiler falls back to the default value.

2. implementation: Why this works

By using the fun _ syntax you change the implementation to a function to a partial applied function. Which will be evaluated when you provide an Int. So it will be not evaluated the same time the val would be evaluated.

So this function will be evalutaed with invocation of the main method. Which will be called when on runs the program.

So adding some print statements (bad style, don't do in prodcution code) will help you to find out the value of the vals at object creation time:

  val factorial: Int => Int = {
    println(s"Before recursive def: $factorial")
    val partialFactorial = factorial(_)
    println(partialFactorial)
    almostFactorial(partialFactorial)
}

Running the second implementation you will then get this output

Before recursive def: null
<function1> <- Partial applied factorial(_)
120

Extended Example: Why using a partial applied function will not automatically protect you here

So the function is null at object creation. If you would provide the value directly in the implementation of the val to the partial applied function as in this example:

  val factorial: Int => Int = {
    println(s"Before recursive def: $factorial")
    val partialFactorial = factorial(_)
    println(partialFactorial)
    println(partialFactorial(2)) // here we will again cause a null pointer exception
    almostFactorial(partialFactorial)
  }

you end up with a null pointer exception again:

$scala Factorial

Before recursive def: null
<function1>
java.lang.NullPointerException
  at Factorial$$anonfun$1.apply$mcII$sp(Example.scala:5)s

Upvotes: 2

Stepan Tsymbal
Stepan Tsymbal

Reputation: 93

You are using higher-order functions here. In that case underscore (_) acts as placeholder. So actually your code:

val factorial: Int => Int = almostFactorial(factorial(_))

Actually can be represented as:

val factorial: Int => Int = almostFactorial( x => factorial(x) )

UPD:

As @Clashsoft added his comment I figured out what happened.

When you define your function as:

val factorial: Int => Int = almostFactorial(factorial)

You're pointing to exact the same instance of factorial over and over. But when you define your function as:

val factorial: Int => Int = almostFactorial(factorial(_))

Scala create another anonymous function which contains your factorial. So it not pointing on itself directly.

Upvotes: 2

Related Questions