I am leaning to program in Scala and came across this problem where Scala code throws StackOverflowErorr while similar implementation in Java can go a bit more before throwing the same error
def recursiveSum(args: Int*): Int = {
if (args.length == 0) 0
else
args.head + recursiveSum(args.tail: _*)
}
recursiveSum(5000 to 15000: _*)
The error i get is
java.lang.StackOverflowError
//| at scala.collection.Parallelizable$class.$init$(Parallelizable.scala:20)
//| at scala.collection.AbstractTraversable.<init>(Traversable.scala:105)
//| at scala.collection.AbstractIterable.<init>(Iterable.scala:54)
//| at scala.collection.AbstractSeq.<init>(Seq.scala:40)
//| at scala.collection.immutable.Range.<init>(Range.scala:44)
//| at scala.collection.immutable.Range$Inclusive.<init>(Range.scala:330)
//| at scala.collection.immutable.Range$Inclusive.copy(Range.scala:333)
//| at scala.collection.immutable.Range.drop(Range.scala:170)
//| at scala.collection.immutable.Range.tail(Range.scala:196)
//| at scala.collection.immutable.Range.tail(Range.scala:44)
//| at Loops$$anonfun$main$1.recursiveSum$1(Loops.scala:11)
//| at Loops$$anonfun$main$1.recursiveSum$1(Loops.scala:11)
//| at Loops$$anonfun$main$1.recursiveSum$1(Loops.scala:11)
//| at Loops$$anonfun$main$1.recursiveSum$1(Loops.scala:11)
//| at Loops$$anonfun$m
//| Output exceeds cutoff limit.
The java code is
static int recursiveSum(int... arg) {
if (arg.length == 0)
return 0;
else
return arg[0] + recursiveSum(Arrays.copyOfRange(arg, 1, arg.length));
}
public static void main(String[] args) {
System.out.println(recursiveSum(range(5000, 15000)));
}
private static int[] range(int i, int j) {
int list[] = new int[j - i + 1];
int idx = 0;
for (int s = i; s <= j; s++)
list[idx++] = s;
return list;
}
Why doesn't Scala's tail recursion optimization help? How come Java can handle (Java could not handle more than 15000 say 16000 as well )?
They are run on same eclipse ide with default stack size of java 7 on desktop machine.
Solution. The simplest solution is to carefully inspect the stack trace and detect the repeating pattern of line numbers. These line numbers indicate the code that is being recursively called. Once you detect these lines, look for the terminating condition (base condition) for the recursive calls.
StackOverflowError is a runtime error which points to serious problems that cannot be caught by an application. The java. lang. StackOverflowError indicates that the application stack is exhausted and is usually caused by deep or infinite recursion.
A stack overflow is a type of buffer overflow error that occurs when a computer program tries to use more memory space in the call stack than has been allocated to that stack.
This isn't tail recursive. In order for the function to be tail recursive the very last statement (the tail) in the function needs to be the recursive call. In your case, it might look like it is, but if you annotate your function with the @tailrec
annotation, you'll see that it isn't. In fact, your last statement is an addition, not the recursive call.
If you rewrite your function to use an accumulator, you'll be able to do a tail recursive version...
def recursiveSum(args: Int*): Int = {
@tailrec
def sumAccumulator(sum: Int, args: Int*): Int = {
if(args.length == 0) sum
else sumAccumulator(sum + args.head, args.tail: _*)
}
sumAccumulator(0, args: _*)
}
recursiveSum(5000 to 15000: _*)
Your function is not formatted properly for tail recursion. You can verify this by (attempting to ) add the @tailrec annotation.
scala> import annotation.tailrec
import annotation.tailrec
scala> @tailrec def recursiveSum(args: Int*): Int = {
| if (args.length == 0) 0
| else
| args.head + recursiveSum(args.tail: _*)
|
| }
<console>:11: error: could not optimize @tailrec annotated method recursiveSum: it contains a recursive call not in tail position
args.head + recursiveSum(args.tail: _*)
^
Here is a working solution:
import annotation.tailrec
def recursiveSum(args: Int*): Int = {
@tailrec def recursiveSumInternal(sum : Int, args: Int*): Int = {
if (args.length == 0)
sum
else
recursiveSumInternal(sum+args.head, args.tail: _*)
}
recursiveSumInternal(0, args: _*)
}
recursiveSum(5000 to 15000 : _*)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With