Feature Request: Private Function Parameters

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.

3 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.

4 Likes