So let’s say you make a tail recursive function like so:
@tailrec
def factorial(x: BigInt, accumulator: BigInt = 1): BigInt = {
if (x <= 1) accumulator
else factorialHelper(x - 1, x * accumulator)
}
I want accumulator to always start at 1 and I don’t want somebody using my code to change that value so being able to do something like:
@tailrec
def factorial(x: BigInt, private val accumulator: BigInt = 1): BigInt = {
if (x <= 1) accumulator
else factorialHelper(x - 1, x * accumulator)
}
instead of having to do:
def factorial(n: BigInt) = {
@tailrec
def factorialHelper(x: BigInt, accumulator: BigInt = 1): BigInt = {
if (x <= 1) accumulator
else factorialHelper(x - 1, x * accumulator)
}
factorialHelper(n)
}
would be a lot quicker and a lot more readable to do. For Java compatibility private function parameters could be converted to the code above too so it’s not an issue.
4 Likes
Something like that may be nice to have, but how often do you really need to make such a tail-recursive function with a helper? I rarely find myself making such helpers, although I don’t speak for everyone.
3 Likes
Well Scala is a functional programming language so you want to use recursion over iteration whenever possible and anything that can be recursive can and should be tail recursive so you don’t deal with the potential stack overflows. With that said the majority of Scala developers will probably at some point use this feature. It’s more readable and faster to write so it might as well be added into the language.
1 Like
Correction:
In the 1st two examples the line:
else factorialHelper(x - 1, x * accumulator)
was meant to be:
else factorial(x - 1, x * accumulator)
Sorry about that haha
It is a common idiom and I like the idea.
I always name the inner thing def loop
because naming is hard.
This syntax support would free me of the naming burden.
private
conveys that the element cannot be referenced from outside.
In particular, factorial(x = base, accumulator = 0)
would be disallowed.
One could define that a positional application is disallowed if the named application is disallowed.
Relatedly, there is a lint for whether a recursive call supplies the “optional” argument or (accidentally) uses the default value. Perhaps a private arg
must be default on entry but must not be default on re-entry. As usual, it could work only for simple recursion, except that it could be enforced for local functions in the body of the recursive method.
Previous tickets for extending value parameter syntax include lazy and def for by-name. I don’t know why lazy args in particular didn’t make progress. The other ticket suggests that val
on a parameter should be allowed as redundant.
5 Likes