From my understanding, the author was complaining about the way default arguments mess up implementations of currying. If default arguments were included in the .length, then all existing currying implementations would carry on working with no modifications, they would just ignore the default values and require that we pass in values explicitly.
Let's say we have these functions:
function getElem(arr, index=0) { return arr[index]; }
var curried = curry(getElem);
In a hypothetical world where default arguments are included in the length, we would have to supply them explicitly. That's no big deal though, it's just a potential inconvenience:
// Hypothetical, "better" semantics
var arr = ["a", "b", "c"];
console.log(curried(arr)); // partially-applied function, *not* "a"
console.log(curried(arr, 0)); // "a"
console.log(curried(arr, 1)); // "b"
The ES6 semantics is worse because we cannot provide a non-default argument to a curried function:
// Actual, "worse" semantics
console.log(curried(arr)); // "a"
console.log(curried(arr, 0)); // Error: attempts to run `"a"(0)`, but "a" is not a function
console.log(curried(arr, 1)); // Error: attempts to run `"a"(1)`, but "a" is not a function
The reason this is particularly unfortunate is that one major use-case of currying is to provide default arguments! In other words, by adding default arguments to the language in this way, ES6 is breaking an existing mechanism for default arguments!
I would argue that currying is actually more general than default arguments, so if it's a choice between one or the other, they should have added currying to the language instead of default arguments.
They're not quite comparable, but you can think of currying as supplying default arguments "dynamically" (at the call site), whereas regular default arguments are supplied "statically" (at the definition site). For example:
// Give "y" a default value for everyone
var defaultMultiply = function (x, y=2) { return x * y; };
console.log(defaultMultiply(5, 7)); // 35
console.log(defaultMultiply(5)); // 10
// Don't commit to any defaults yet
var curryMultiply = curry(function(x, y) { return x * y; });
console.log(curryMultiply(5, 7)); // 35
// Give "x" a default value, to act like defaultMultiply
var double = curryMultiply(2);
console.log(double(5)); // 10
// Give "x" a different default, which we can't do with defaultMultiply
var triple = curryMultiply(3);
console.log(triple(5)); // 15
I've implemented and used currying in JS, PHP and Python, and I found JS the most pleasant, specifically because it didn't have default values.
Very well said. I work on the Ramda (http://ramdajs.com/) FP JS library with the OP. Ramda is heavily invested in currying, and I don't yet have a clue how we'll deal with default parameters. At first guess, we'll simply have to explain that we can't curry such functions. Such a shame!
Let's say we have these functions:
In a hypothetical world where default arguments are included in the length, we would have to supply them explicitly. That's no big deal though, it's just a potential inconvenience: The ES6 semantics is worse because we cannot provide a non-default argument to a curried function: The reason this is particularly unfortunate is that one major use-case of currying is to provide default arguments! In other words, by adding default arguments to the language in this way, ES6 is breaking an existing mechanism for default arguments!I would argue that currying is actually more general than default arguments, so if it's a choice between one or the other, they should have added currying to the language instead of default arguments.
They're not quite comparable, but you can think of currying as supplying default arguments "dynamically" (at the call site), whereas regular default arguments are supplied "statically" (at the definition site). For example:
I've implemented and used currying in JS, PHP and Python, and I found JS the most pleasant, specifically because it didn't have default values.