A Reasonable Development at SmartLogic

Over the past year, ReasonML has picked up steam within the communities we follow. We've recently embraced it at SmartLogic to help us build robust web and mobile applications for our clients.

What is Reason?

Reason lets you write simple, fast and quality type safe code while leveraging both the JavaScript & OCaml ecosystems.

-- Reason Homepage

What does this mean?

Think of Reason as a syntax for OCaml that compiles to JS. Reason is syntactically similar to JS on purpose, and as big JS devs, we found it familiar and welcoming from the start.

Why use it?

There are plenty of reasons, but the bottom line is that it takes advantage of decades of OCaml and JS engineering to give us a solid and simple yet performant language. Among the most compelling features are:

  • Types! - We know the importance of typing our JS and often accomplish this with Flow, but now we have first-class type safety.
  • Object-functional - Reason is mostly immutable and functional but allows side effects and mutations at your discretion.
  • Familiar ecosystem - Everything we know and love about the JS world is easily available in Reason land, where interoperability is a priority.
  • Incrementally adoptable - It's not necessary to rewrite your entire codebase to add Reason. You can start at a single file.

What does it look like?

How about an example? Below is some Reason code to recursively compute the nth fibonacci number using memoization. Notable features in this snippet include types (of course!), pattern matching, and labeled function arguments.

type memo = Hashtbl.t(int, int);

let rec f = (~n: int, ~memo: memo): int => {
  let result =
    switch n {
    | x when x <= 0 => 0
    | x when x <= 2 => 1
    | x =>
      switch (Hashtbl.find(memo, n)) {
      | y => y
      | exception Not_found =>
        f(~n=(x - 1), ~memo) + f(~n=(x - 2), ~memo);
      };
    };
  Hashtbl.add(memo, n, result);
  result;
};

let fibonacci = (n: int): int =>
  f(~n, ~memo=Hashtbl.create(~random=true, n));

This generates the following JS:

// Generated by BUCKLESCRIPT VERSION 2.1.0, PLEASE EDIT WITH CARE
'use strict';

var Hashtbl                 = require("bs-platform/lib/js/hashtbl.js");
var Caml_builtin_exceptions = require("bs-platform/lib/js/caml_builtin_exceptions.js");

function f(n, memo) {
  var result;
  if (n <= 0) {
    result = 0;
  } else if (n <= 2) {
    result = 1;
  } else {
    try {
      result = Hashtbl.find(memo, n);
    }
    catch (exn){
      if (exn === Caml_builtin_exceptions.not_found) {
        result = f(n - 1 | 0, memo) + f(n - 2 | 0, memo) | 0;
      } else {
        throw exn;
      }
    }
  }
  Hashtbl.add(memo, n, result);
  return result;
}

function fibonacci(n) {
  return f(n, Hashtbl.create(/* Some */[/* true */1], n));
}

exports.f         = f;
exports.fibonacci = fibonacci;
/* No side effect */

Not obfuscated--pretty readable, in fact! This is just a quick glance at what Reason provides, so be sure to check out their docs for a full list of features!

How does it work?


Credit: 2ality*

Reason is parsed through the OCaml AST and, using Bucklescript, gets compiled to JS. As seen in the diagram, JS is not the only supported compile target though it currently benefits from the most support.

*2ality is an excellent blog by Dr. Axel Rauschmayer with an informative series of posts on Reason.

What should I keep in mind?

While there haven't been many pain points, we did notice a few:

  • Asynchronous utilities - You won't find an abstraction analogous to JS async/await quite yet, but there are promise bindings.
  • JSON utilities - Like promises, there are JSON bindings, but working with JSON still feels a bit clunky.
  • Still evolving - Everything continues to mature, from syntax to paradigms. This is not necessarily a drawback however, as there is a growing list of respectable production users.

Conclusion

Our experience with Reason thus far has been overwhelmingly positive. Wonderful docs and a passionate community helped make our adoption smooth and enjoyable, and we're excited to continuing building with it. Stay tuned for a future blog post on an example app we're building with Reason!