This article is an excerpt from my upcoming book about Data Oriented Programming. The book will be published by Manning, once it is completed (hopefully in 2021).

More excerpts are available on my blog.

Enter your email address below to get notified when the book is published.


Constraining our programs to manipulate immutable data structures is known to be beneficial in terms of code predictability, concurrency and safety.

In a language like Clojure, where immutable data structures are native to the language, this benefits come for free. However, in languages where immutable data structures are not native to the language, the price we have to pay to benefit from data immutability is that we need to convert the data back and forth from immutable to native. Beside the inconvenience of this conversion, it might cause a performance hit, it we are not careful with the conversion.

Car

The purpose of the is article is to illustrate how to manipulate carefully immutable data collection from Immutable.js with the a data manipulation library like Lodash.js, leveraging Immutable’s shallow and deep conversion functions.

A similar approach could be applied to other immutable data collection libraries and other data manipulation libraries (and also to other programming languages).

Imagine we have a nested piece of data that we want to:

  1. Treat as immutable (e.g Immutable.js)
  2. Manipulate with data manipulation library (e.g Lodash.js)

The challenge is that Immutable.js data collections are not native JavaScript objects. Therefore, before passing the data to a JS lib, we have to convert it to a JS object. In this article, we are going to show how to convert to JS without impacting the performance too much.

Let’s take as an example the data of a library, that might looks similar to this nested object:

var libraryData = {
  "name": "The smallest library on earth",
  "address": "Here and now",
  "catalog": {
    "books": [
      {
        "title": "Watchmen",
        "publicationYear": 1986,
        "authors": [
          {
            "firstName": "Alan",
            "lastName": "Moore"
          },
          {
            "firstName": "Dave",
            "lastName": "Gibbons"
          }
        ]
      },
      {
        "title": "Jimmy Corrigan, the Smartest Kid on Earth",
        "publicationYear": 2000,
        "authors": [
          {
            "firstName": "Chris",
            "lastName": "Ware"
          }
        ]
      },
      {
        "title": "Ultimate Spider-Man",
        "publicationYear": 2000,
        "authors": [
          {
            "firstName": "Brian Michael",
            "lastName": "Bendis"
          }
        ]
      }
    ]
  },
  "users": [
    {"username": "user-1"}, {"username": "user-2"}, {"username": "user-3"}
  ]
}

Now, we convert the native JS object to an Immutable map with fromJS():

var immutableLibData = Immutable.fromJS(libraryData);

Our purpose is to find the best way to call _.countBy() on our immutable collection, in the same way as we would use it on the JS native object:

_.countBy(immutableLibData.toJS().catalog.books, "publicationYear"); 

Immutable.js provides a .toJS() function that deeply converts an immutable collection to a JS object or array.

We are then free to pass immutableLibData.toJS() to any Lodash function:

_.countBy(immutableLibData.toJS().catalog.books, "publicationYear"); 

The problem is that it causes a performance hit, as we have to convert the whole immutableLibData immutable collection (including the users part which is unnecessary)

A better solution is to convert only the part of the data that we are interested in:

_.countBy(immutableLibData.getIn(["catalog", "books"]).toJS(), "publicationYear");

But still, there is a performance hit as we convert the books data deeply (including the authors part which is unnecessary).

The best thing we can do, is to do a careful shallow conversion to native JS: It requires 2 steps:

  1. Shallow convert books to a JS array with Immutable’s toArray()
  2. Shallow convert each object of the books array to a JS object with Immutable’s toObject()

Here is the code for that:

function toArrayofObjects(m) {
  return m.toArray().map(x => x.toObject());
}

And now, we can use _.countBy() with no unnecessary performance hit:

_.countBy(toArrayofObjects(immutableLibData.getIn(["catalog", "books"])), "publicationYear");

A similar approach could be applied to other immutable data collection libraries and other data manipulation libraries (and also to other programming languages). The features that the immutable data collection library needs to provide are:

  1. Deep conversion to native objects (like Immutable toJS())
  2. Shallow conversion to native objects (like Immutable toArray() and toObject())

Enjoy immutability!

This article is an excerpt from my upcoming book about Data Oriented Programming. The book will be published by Manning, once it is completed (hopefully in 2021).

More excerpts are available on my blog.

Enter your email address below to get notified when the book is published.