Private function arguments for creating closures implicitly

I just wrote my first ECMAScript proposal, providing a convenient way for protecting tail recursive function parameters from modification by the caller. For further details, please check out the corresponding repository.

As a brief example, the code below:

// From the outside, the function below only takes a single argument
function fact(n, #acc = 1) {
  if (n > 0) return fact(n - 1, n * #acc);
  return #acc;
}

Could be transformed to:

function fact(n) {
  // A closure is defined explicitly to protect `acc` from unwanted modification
  function fact_inner(n, acc) {
    if (n > 0) return fact_inner(n - 1, n * acc);
    return acc;
  }
  return fact_inner(n, 1);
}

What would the arguments keyword do? How would it work with a rest argument? Do you have to provide a default?

That transformation would result in fact referring to two distinct identities; what happens if one property is stuck on it from outside, and another from inside - is there an object that has both properties on it, or two objects, each with one?

In order to retain backwards compatibility, the arguments keyword should only contain public arguments, leaving related parts of the specification intact. The rest argument case has been outlined in the repository.

Private function arguments may not be rest parameters (e.g. #...param). It would not make sense for any use-case. Mostly, a single private argument should be enough for a function.

Default values are optional, but recommended for clarity. We may consider making them required, though.

From the caller side, fact should act like it only has a single argument. When more than one parameters are provided, the rest shall not override any private arguments, but make it to the arguments keyword. For example, fact(3, 999) would call fact_inner(3, 1) as #acc must be kept intact. However, in this case, the arguments keyword should contain [3, 999], just as if 999 was provided as a public rest parameter.

Can you explain why this is better than just having two functions, only one of which is exposed publicly?

Firstly, for improved readability and less nesting. The code with private fields has a structure identical to its counterpart with public fields (function fact(n, acc = 1) { /* ... */ }).

In addition to this, declaring only a single function offers an optimization opportunity for engines like V8.

There's nothing extra here to do aside from saving a stack frame (for the engines that don't follow spec on PTC like V8 and SpiderMonkey, but not JSC).

And since they already don't implement tail calls in the first place, the utility of this is further limited.

When coming up with the proposal, improving the readability of recursive code was my primary goal. Performance is not in the spotlight this time. JavaScript doesn't have function overloading, and this proposal tries to lower the amount of closures required by introducing a similar concept without breaking existing code.

There's hardly a use case where you couldn't just write

export function fact(n) {
  return fact_rec(n, 1);
}
function fact_rec(n, acc) {
  if (n > 0) return fact_rec(n - 1, n * acc);
  else return acc;
}

instead. It would have the same advantages for performance and readability, I'd even argue that it is more readable without introducing curious "private parameter" syntax that would be seldom used.

I believe that code readability is cannot be justified unless measured with a scientific approach. Syntactic additions may be disabled with linters when undesired.

Experimentation with a new syntax may open up new perspectives and opportunities. Currently, the # operator has only been utilized for classes. My primary goal is to provide more value for functional programming with this proposal.

While the two separately defined functions of yours take advantage of file-scoped exports, I would like to make private arguments unchangeable even from the same file, except when accessed from the body of the owning function.