Tail call optimization for JavaScript!
npm install babel-plugin-tailcall-optimization --save-dev
and add to your .babelrc
:
"plugins": ["tailcall-optimization"]
if you use babel@6 use babel-plugin-tailcall-optimization@1
package
We rewrite functions with tail calls to ones using while loops. Original function with tail call:
function counter (n, acc = 0) {
if (n === 0) {
return acc
} else {
return counter(n - 1, acc + 1)
}
}
gets rewritten to this:
function counter(n, acc = 0) {
var _repeat = true;
var _n, _acc;
while (_repeat) {
_repeat = false;
if (n === 0) {
return acc;
} else {
_n = n - 1
_acc = acc + 1
n = _n
acc = _acc
_repeat = true;
continue;
}
}
}
Plugin does not affect functions without TCOs so it's safe to use.
For Fibonacci Sequence example benchmark.js results are:
Fibonacci Sequence without TCO x 270,170 ops/sec ±1.14% (85 runs sampled)
Fibonacci Sequence with TCO x 1,298,276 ops/sec ±1.24% (83 runs sampled)
So function after TCO optimization is almost 5 times faster.
-
Currently when plugin detects function creation within tailcalled function it does not optimize it. It's related to difficulties in implementation (function scoping rules). Read more: https://phabricator.babeljs.io/T6869
-
It does not work for mutual recursive functions. I guess it's not super big problem - even JVM does not do this.