Our Product Design Process book is out now!

ORDER NOW

ReasonML - React as first intended (2020)

This post was originally posted in May 2018 by Pedro Rolo and updated in May 2020 by André Santos.

When one thinks about ReasonML, the fact that it's backed by Facebook, does not tell it all. It's a technology that evolved over the last couple of years with a lot of potential, not only due to the influence of JavaScript tools, but also on a compiler to native code perspective.

In this article, I’ll take a closer look at it's genesis and how other technologies, like React, BuckleScript or OCaml shaped its development.

What is ReasonML?

ReasonML is the new tech that Facebook is using to develop React applications and promoting as a futuristic version of JavaScript (ES2030 they say).

In a nutshell:

  • A new way to write React applications;
  • A JavaScript-friendly syntax for the OCaml semantics;
  • Statically typed - with type inference;
  • Functional, but not pure;
  • Mainly compiled to JavaScript;
  • Backed by Facebook and Bloomberg.

How React shaped ReasonML

React's programming style is much closer to functional than to object-oriented programming. It's thus not surprising to discover that the first React prototype was not implemented in JavaScript, but in Standard ML instead.

However, as the prototype was starting to mature, it's author, Jordan Walke, decided to port it to JavaScript and continue from there. There were no mature transpilers to JavaScript and also, back then, the world wasn't ready to accept such a non-mainstream programming language and style.

As a result, React became popular as a technology linked to the JavaScript programming language.

Despite this success within the JavaScript ecosystem, some people started to feel that there was something going on behind the scenes. Other related projects - such as Redux, Elm and Purescript - started to gain popularity, thus pushing the community's mindset closer to the originally functional and statically typed roots of React.

This made Facebook believe that it could be feasible and convenient to move React itself closer to its roots.
Eventually, they found that a lot of the groundwork was already layed out for them...

Starting with BuckleScript

Some companies are developing such mission critical user interfaces that using dynamic or gradually typed languages could represent unbearable losses.

Bloomberg is one of such companies. It was for Bloomberg that Hongbo Zhang was working and experimenting with the JavaScript runtime, when he realized that it was not difficult to port the OCaml compiler to JavaScript and run it on the browser.

(* A Factorial implementation in BuckleScript / O'Caml *)
let rec factorial n =
  if n <= 0 then
    1
  else
    n * fact(n-1)

The reality was that the OCaml compiler was already very modular. It wasn't very hard to replace its native-code-generating backend by a javascript-generating one. With such backend, it was even possible to compile the OCaml compiler into JavaScript, thus self-hosting the BuckleScript compiler and running it in the browser.

BuckleScript was born and better yet, it was released by Bloomberg as open source software.

(* A FizzBuzz implementation in BuckleScript /  O'Caml *)
let fizzbuzz i =
  match i mod 3, i mod 5 with
    | 0, 0 -> "FizzBuzz"
    | 0, _ -> "Fizz"
    | _, 0 -> "Buzz"
    | _    -> string_of_int i

let _ = for i = 1 to 100 do
  print_endline (fizzbuzz i)
done

It's important to notice that the original OCaml compiler had already decades of development and optimizations done by the Institut National de Recherche en Informatique et en Automatique (INRIA). It was one of the fastest compilers available for such an heavily type checked language.

From BuckleScript to ReasonML

If Facebook intended to make the React ecosystem statically typed, BuckleScript was certainly a nice candidate. They seemed to believe that JavaScript - with its popular curly braced syntax - was largely responsible for React's success.

// A Factorial implementation in ReasonML
let rec factorial = (x) =>
  if (x <= 0) {
    1;
  } else {
    x * factorial(x - 1);
  };

However, they weren't naïve enough to simply take BuckleScript with its OCaml syntax. They rather kept the OCaml semantics, the BuckleScript backend and as much as they could from the JavaScript syntax.

In order to keep the JavaScript syntax they created an additional parser, handling a new language called ReasonML.

We can say that is Reason ML is simply OCaml with a javascript-like curly-braced syntax.

// A FizzBuzz implementation in ReasonML
let fizzbuzz = (i) =>
  switch ([i mod 3, i mod 5]) {
    | [0, 0] => "FizzBuzz"
    | [0, _] => "Fizz"
    | [_, 0] => "Buzz"
    | _    => string_of_int(i)
  };

for (i in 1 to 100) {
  print_endline(fizzbuzz(i));
};

The result is surprisingly similar to JavaScript. To the point that some JavaScript code can be directly processed by the compiler, as if it was ReasonML, with all the benefits that a statically typed compiler has and no code change whatsoever.

// Both valid ReasonML and Javascript code
let add = (a, b) => a + b;
add(4, 6);

ReasonML and React

Besides the work on the language and compiler itself, Facebook has also devoted some effort into developing a ReasonML wrapper around its React framework, with an additional functionality.

It's called React Reason. It makes it easier to mix JavaScript React components with Reason components within the same ReactJS or Reason application.

It should be noticed that React Reason isn't just a wrapper around React. It also provides some out-of-the-box functionalities that used to come with external libraries such as Redux and Immutable.

ReasonML and Redux

Redux is a state manager that's very popular amongst React projects. Simply put, it allows organizing the application domain logic as a set of composed reducer functions, which are meant to express how the state of the application should be transformed as external events (such as user interactions).

When using ReasonML, we don't need Redux anymore.

ReactReason stateless components already come with the concept of a built in reducer, which is meant to take care of the problems Redux used to address.

/*
 * A simple incrementing counter in React Reason
 * try it at: http://bit.ly/counter-button-sample
 */

type state = {count: int};

type action =
  | Click;

let component = ReasonReact.reducerComponent("Counter");

module Counter = {
  let make = _children => {
    ...component,

    initialState: () => {count: 0},

    reducer: (action, state) =>
      switch (action) {
      | Click => ReasonReact.Update({count: state.count + 1})
      },

    render: self => {
      let message =
        "Clicked "
        ++ string_of_int(self.state.count)
        ++ " times(s)";
      <div>
        <button onClick=(_event => self.send(Click))>
          (ReasonReact.string(message))
        </button>
      </div>;
    },
  };
};

ReasonML and Immutable

The functionality that used to be provided by Immutable is implemented at the language-level.
ReasonML (and OCaml) operations are immutable by default, thus avoiding the cognitive and performance overheads of using an external library.

ReasonML vs Elm

A while ago I've written about the Elm language. Well, ReasonML and Elm they are not that different from each other.

Analyzing their differences in depth it's out of the intended scope of this article, but - in sum - they stem from a different stance about functional purity and level of maturity of both projects.

Below you can find a tabular summary of how their traits match and how they differ:

Common traits

  • Functional programming;
  • Compiled to JavaScript;
  • Safe;
  • Short feedback loop;
  • Easy to test and reactor;
  • Full-coverage, inferred static typing.

Differences

Reason vs Elm Summary

Compilation to Native Code

As you may notice on the table above, it's mentioned that ReasonML can be compiled to different targets, including native code. That can be done by using the ReasonML syntax layer with the remaining original OCaml compiler, including the original native-code backend.

There's plenty of potential here. Eventually allowing to share Reason's code amongst the backend and frontend or even compiling the backend to native code.

Which companies use ReasonML?

The flagship application for ReasonML is Facebook Messenger, which originally was a ReactJS application that has been progressively migrated to ReasonML. Additionally, ReasonMl's adoption extends beyond Facebook's projects and there are plenty of other companies that use it. Some of them are mentioned on listed in the ReasonML's documentation page.

Reasoning for ReasonML

ReasonML seems like another iteration, over the same efforts, to bring a functional statically typed language into the JavaScript ecosystem.

Nevertheless, the direction taken by this project and its backers seem much more promising both from marketing and technological points-of-view.
It can take advantage of JavaScript's tools and relaxed syntax while leveraging on the work done for OCaml, without forgetting that it's backed by Facebook. Also, there's the potential to reach different platforms and environments through BuckleScript.

While ReasonML is not the first and certainly not the last to try to tackle these goals, it presents itself as an enterprise-grade attempt, trying to appeal to the taste of the mainstream.

Found this article useful? You might like these ones too!

At Imaginary Cloud, we simplify complex systems, delivering interfaces that users love. If you’ve enjoyed this article, you will certainly enjoy our newsletter, which may be subscribed below. Take this chance to also check our latest work and, if there is any project that you think we can help with, feel free to reach us. We look forward to hearing from you!