I stumbled upon this very interesting article on the concept of currying and how to it in practice, I definitely recommend you read it =).
As I am very interested in the performance cost of how we program, I had to explore the impact of using this method/feature or whatever we want to call it, here are my findings.
Test 1 (add)
Curried Version (from the referenced article, using lodash)
function add(a, b, c) {
return a + b + c;
}
const curryAdd = _.curry(add);
curryAdd(1)(2)(3);
Basic JS Version
function add(a, b, c) {
return a + b + c;
}
add(1, 2, 3);
And the results are just horrible. Using the curried version here is 99.96% slower, its so slow its almost unfathomable.
Test 2 (isType)
Base Items List for this test (from the referenced article)
const items = [
{ name: "Mango", type: "Fruit" },
{ name: "Tomato", type: "Vegetable" },
{ name: "Strawberry", type: "Fruit" },
{ name: "Potato", type: "Vegetable" },
{ name: "Turnip", type: "Vegetable" },
{ name: "Banana", type: "Fruit" },
{ name: "Carrot", type: "Vegetable" },
];
Curried Version (from the referenced article)
const isType = obj => type => obj.type === type;
const isFruit = item => isType(item)("Fruit");
const isVegetable = item => isType(item)("Vegetable");
const fruits = items.filter(isFruit);
const vegetables = items.filter(isVegetable);
Basic JS Version
function isFruit(obj) { return (obj.type == 'Fruit'); }
function isVegetable(obj) { return (obj.type == 'Vegetable'); }
const fruits = items.filter(isFruit);
const vegetables = items.filter(isVegetable);
Performance here is IDENTICAL for both versions which is nice, and expected, since you end up with basically the same thing for .filter to do.
Wrap Up
As is illustrated in the referenced article there are certainly use cases for currying, but do use it with restraint, especially if your code is executed by many many people, or many many times.
--
All benchmarking done with https://jsbench.me/ in the latest version of Chrome on a Windows PC. Actually declaring the functions was NOT included in the benchmarked code, that happens in the setup stage. That is slower in the curried case for both tests above.
Top comments (2)
The
add
example is pretty surprising! I wonder if the interpreter is inlining the uncurried version, so it's not actually doing any function calls.Something is definitely going on there to make it such a huge difference. It would be interesting to see a breakdown of what actually happens in the JIT compiler and what the actual executing code ends up being.