A defense of functional javascript

The dominant programming paradigm for the web currently is the imperative Object Oriented style. People use it in Java, use it in Python and some even risk themselves trying it in Javascript. Many of us have struggled hard to understand several concepts, such as polymorphism, inheritance and method overloading; some also have studied the ways of design patterns and the famous Gang of Four book to learn the advanced techniques for composing together the pieces of the Object Oriented designs we build.

So much effort makes it difficult for us to look at OOP as not being the only available production ready option, and not even the best one. Javascript has an extremely flawed OOP support, besides the flaws of the paradigm itself. Here I expose my recent opinion about the topic, and why I believe we all should be writing functional javascript, not thinking on objects.

First of all, OOP encourages mutability, which is a known source of complexity in medium to large systems. By coupling operations (methods) with their related data (attributes), we create little units of state spread throughout the system. As the codebase grows, it gets more and more difficult to answer a simple question: “what is going on inside the application?”.

By coupling data with actions, we lose the ability to compose behaviour, and instead, go on composing objects. But the problem is that objects are both, behaviour and data, so we end up with a complex state spread in various places as we put together all the building blocks.

Add to the equation the fact that the javascript implementation of object orientation is far less than ideal. It overloads functions to act as both constructors and transformations, differentiate them with the “new” keyword, and have various problems with “this” binding.

Because functions are overloaded that way, whenever we create a function, we also create a context for “this”, based on whether the function is being called as a simple function, a constructor or a method. Things go really wild as we need to mix method/constructor functions with simple ones, and often we need to use a famous idiom, one that people use so much that they don’t feel like they’re doing something strange:

Foo.prototype.bar = function() {
  var self = this; //see how it's AWFUL?
  something.act(function() {
    self.baz();
  });
}

Let’s face it: Javascript is NOT meant to be used in an OOP style. It is a functional language, based on scheme, with a terrible java friendly syntax. It has first class functions (functions are values, like numbers or strings), has higher order functions and support arbitrarily nested closures.

Functional programming, makes you think about your program as compositions of pure functions (functions that only read their arguments and compute a value, with no side effects), providing a better solution for state control and complexity management.

But not everything are flowers, and javascript also has some problems for functional development, specially about immutability. In the javascript world, where there are no immutable data structures, we can use facebook’s Immutable.js, or mori, or even the less robust ES5’s Object.freeze method, and keep structuring our code around pure functions.

To help differentiate the two paradigms, imagine you have the following story in OOP style:

function Cat() {
  this.catchedMouse = null;
}
Cat.prototype.catch = function(mouse) {
  this.catchedMouse = mouse;
}
Cat.prototype.eat = function() {
  if (this.catchedMouse) {
    this.catchedMouse.die('eaten by a cat'); 
    this.catchedMouse = null;
  }
  else {
    throw new Error('Cannot eat without a catch');
  }
}

function Mouse() {
  this.isAlive = true;
  this.deathCause = null;
}
Mouse.prototype.die = function(cause) {
  this.isAlive = false;
  this.deathCause = cause;
}

var tom = new Cat();
var jerry = new Mouse();
tom.catch(jerry);
tom.eat();

Here we have a cat eating a mouse, modeled as two “classes” (yes, I know javascript does not REALLY have classes, but for some reason people want so much to believe it has that we even got a syntax sugar for that in ES6). First we instantiate the cat and mouse objects, put a state inside the cat object: the catched mouse; Then, when we invoke the method eat, we recover that same mouse and alter it’s internal state.

Now, look at the same story, told in a functional way:

//no constructor function
//we only return a data structure representing a cat
var makeCat = function() {
  return {eaten: []};
};

//we represent state change by returning another
//structure, with the altered content
//without mutating the original inputs
var capture = function(mouse){ 
  return function(cat) {
    return {eaten: cat.eaten, capture: mouse};
  };
};

var makeMouse = function() {
  return {dead: false};
};

var kill = function(causeOfDeath, victim) {
  return {
    dead: true, 
    causeOfDeath: (victim.causeOfDeath || causeOfDeath)};
};

var eat = function(catWithCatch) {
  var eaten = catWithCatch.eaten || [];
  if (catWithCatch.capture) {
    return {
      capture: null,
      eaten: eaten.concat(kill('eaten by a cat', catWithCatch.capture))
    };
  }
  else {
    return new Error('need a captured mouse to eat');
  }
};

var tom = makeCat();
var jerry = makeMouse();

eat(
  capture(jerry)(
    tom));

Here we have modeled the story around the actions, using functions. There is a catch function, a kill function and an eat function. All of them only creates data representing the state of the computation as the result, there is no variable mutation at all.

Also, as all functions are pure, we can reuse them, say, if we need to model a wolf eating that poor cat. Note that all the times we returned a data structure based on another, we can go very performant (and less verbose) using a library of immutable data, like the ones I mentioned earlier.

If we can isolate the change, control the computation as purely as possible, and organize our code as a flow of transformations on data, instead of a mix of mutations on variables; we can reason about the code much easily, and pleasantly; we can reuse more code than we usually could with OOP and finally, we can be much more confident about our craft.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s