ÆFLASH

Functional Javascript

As I code more and more, I'm coming to find that traditional Object-Oriented techniques aren't well suited to Javascript. OO techniques really shine when you have a compiler to tell you that Foo does not have a method named bar(), and that bar() expects an object that implements interface Qux with methods baz() and bogo(), etc... In JS it is impossible to know what the properties of an object will be until runtime, or what its type will be. (This really frustrates a lot of my coworkers who like strongly-typed languages.) Tools and IDE's can make some fairly good assumptions, but they always seem to fall short -- either your code has to be written in a restrictive style so every property is detected, or you have to accept that certain dynamic properties will not be picked up.

This is not to say that static analysis of JS is useless, in fact I am a big fan of JSHint, especially the unused and undef options. Here is an example:

var
  Foo = require("./Foo"),
  Bar = require("./Bar"), // Bar is not used, so JSHint will complain
  Baz;

module.exports = Baz = function () {
  // constructor...
}

_.extend(Baz.prototype, Foo.prototype);

Baz.prototype.qux = function (something) { // something is unused
  this.foo = somehting.getFoo(); //"somehting" is undefined because I typo'd it

  return this.bar + this.foo; // no way to know if these properties exist until runtime
}

JSHint helps out with explicit variables and arguments, but falls short with properties of objects. (I also use this example to show just how clunky creating classes are in JS. ES6 will fix this, but for the time being, just replicating class Baz extends Foo is not obvious and there are a million ways to do it wrong.) Some JS IDEs are really clever in detecting methods and properties, but I don't see how any IDE could efficiently handle something like this:

_.each(JSON.parse(fs.readFileSync(configFile)), function (prop, key) {
  this["get" + key] = function () {
    return prop + this.foo;
  };
}.bind(this));

It literally would have to execute the module to know what those dynamic properties would be.

Situations like these have made me realize that it is better to write JS in more of a functional style, rather than try to shoe-horn traditional OO into javascript.

That being said, I'm not saying you should write JS like it is Lisp, and eschew objects altogether. There is a really cool thought experiment in JS: List out of Lambda. It is a good introduction to creating constructs from pure functional building blocks. However, the obvious thing to point out is that if you actually were to use those pure-functional lists, they would be terribly slow. Functional languages like Lisp, Haskell, or Clojure rely on the compiler to do optimizations that make things as fast as imperative languages like C or Java. Interpreted Javascript cannot make these optimizations (yet, at least).

Here are my reccommendations, my list of currently unsubstantiated claims. Each one of these bullet points could be an article on its own:

  • Use built-in Objects and Arrays. Rather than creating lists out of lambda, using the built in "collection" types is a logical place to draw the functional line. A good tradeoff between speed and functional purity.
  • Use higher-order functions. Rather than explicit iteration, get used to each, map, filter, reduce, compose, and all the methods of Underscore. Also, write your own functions that mutate other functions when you find yourself writing the same code over and over.
  • Avoid using this. this is really an implicit argument passed to every function. It's hard to know what its properties are until runtime. However, if every variable or argument is explicit -- not contained within an object -- JSHint can detect problems statically.
  • Avoid state. Related to the previous point, if you're using this, you are probably creating state. If you do need state, pass it in as an explicit argument, or encapsulate it in as small of an object as possible.
  • Write pure functions. In a perfect world, calling a function should have no side effects. If a function does not modify its arguments or any external state, and returns a completely new result, is considered "pure". Think const in C. Pure functions are also very easy to test.
  • Create functions that operate on data structures, rather than objects that encapsulate data structures. Think getNameFromConfig(jsonConfig) rather than var config = new Config(json); config.getName(). In this example, getNameFromConfig is a pure function.
  • Master call, apply, bind, partial application, and currying. These are all powerful functional programming techniques that allow you to use higher-order functions more effectively.

I will reiterate that these are more of guidelines than actual rules. For example, avoiding state completely is impossible: using JS to add a DOM Element is changing the state of the browser. However, the core of your system could strive to be as stateless as possible -- you could rely purely on events rather than reading state variables and flags.

There are three follow-up articles I will write in the future to expand on this topic:

  • Show how functional javascript solved a common problem: Fixing callback hell in Node.
  • Refactoring an object-oriented, imperative module into a more functional-styled module
  • Creating a functional Vanilla-JS example for TodoMVC

code javascript functional programming