Power of expression vs. Performances

map and reduce are the basic building blocks of functional programming.

The essence of map and reduce is that they give you - the developer - more power of expression over the equivalent piece of code using a while or a for loop.

And the power of expression is an important part of SW development.

But very often, there is a trade-off between power of expression and performances. It’s the case with reduce in javascript. But, fortunately, Clojurescript comes to the rescue with its super-powerful macros and we - the clojurescript developers - enjoy both high performances an the power of expression.

In this article, we show illustrate this idea dealing with a function that calculates the sum of the squares of an array of numbers.

Car

javascript: reduce vs. for loop

Let’s compare the performances of reduce and for for sum-of-squares, with KLIPSE.

In this article, we are going to mix clojurescript and javascript interactive code snippets.

All the code snippets of this page are live and interactive powered by the klipse plugin:

  1. Live: The code is executed in your browser
  2. Interactive: You can modify the code and it is evaluated as you type

First, the reduce implementation:

function sum_of_squares_reduce_js(arr) {
        return arr.reduce(function(res, val) {
                    return res + val * val;
                        }, 0);
}
sum_of_squares_reduce_js([1,2,3])

And the for loop implementation:

function sum_of_squares_for_js(arr) {
      var res=0;
        for(var i=0; i < arr.length; i++){
                res = res + arr[i] * arr[i];
                  }
                    return res;
}
sum_of_squares_for_js([1,2,3])

Now, let’s compare the performances of reduce vs. for:

(def n 1000000)
(def js-arr (to-array (range n)))

(time (js/sum_of_squares_reduce_js js-arr))
(time (js/sum_of_squares_for_js js-arr))

In javascript (at least in Chrome on August 2016), reduce is much slower than for.

Feel free to modify js-arr to benchmark as you wish.

Someone wrote in the comments that on Firefox, reduce is faster than for.

If you are on another browser, please write in the comments what are the performances on your browser….

Clojurescript areduce

In clojurescript there is a handy way to reduce over native arrays.

Please welcome areduce.

With areduce you pass an expression instead of a function

(areduce a idx ret init expr)

areduce reduces an expression across an array a, using an index named idx, and return value named ret, initialized to init, setting ret to the evaluation of expr at each step, returning ret.

Obviously, areduce is a macro.

It sounds complex, but with an example it will be very clear. Let’s implement our sum of squares using areduce and have a look at the transpiled javascript code:

(defn sum-of-squares-clj-areduce [xs]
  (areduce xs i ret 0
             (+ ret (* (aget xs i) (aget xs i)))))

Observe the transpiled javascript code: It’s very close to the implementation, you’d have written for sum-of-squares, before reduce was available in javascript. (Maybe you’d chosen better names for the variables.)

From the power of expression perspective, areduce is as powerful are reduce.

We will investigate the performance of areduce in the next paragraph.

Clojurescript areduce vs. Javascript reduce

Now, it’s obvious why areduce is faster that javascript’s reduce: areduce is a macro that allows you - the developer - to write elegant code that is translated at compile time to fast native code.

Let’s see it in action with KLIPSE.

(defn sum-of-squares-clj-areduce [xs]
  (areduce xs i ret 0
             (+ ret (* (aget xs i) (aget xs i)))))

(time (sum-of-squares-clj-areduce js-arr))

In clojurescript, areduce is as fast as for in javascript

Clojurescript rocks!