Reputation: 1227
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
Reputation: 10894
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 val
s are instantly evaluated. So the compiler falls back to the default value.
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
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
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