Release 1.7 and the story behind BuckleScript

Bloomberg Engineer Hangbo Zhang photographed in New York at Bloomberg on May 15, 2017. Photographer: Lori Hoffman/Bloomberg

At the Compose Conference 2017 in New York City later this week, BuckleScript author Hongbo Zhang, a senior programmer here at Bloomberg, will deliver his first formal conference presentation about BuckleScript and how this optimizing compiler makes functional programming more accessible to JavaScript developers. Ahead of his talk at the conference, we wanted to let him share details about the latest update to the platform.

It has been a while since we announced the release of BuckleScript 1.0, and the quality of the BuckleScript compiler and its build system have improved significantly since then.

As an engineer, I would prefer solving challenging technical problems to writing articles. However, this release includes several large improvements and I believe BuckleScript has reached the point where it may be the state-of-art Alt-JS compiler. So I decided to spend some time writing about this release and sharing my story about BuckleScript and JavaScript.

My experience with JavaScript

As a developer who knew very little about Web UI development, I was shocked by the power and reach of the JavaScript platform. Back in 2012, when I saw the entire OCaml compiler could be hosted in a browser and run very smoothly, it truly surprised me, especially given the complexity of the compiler. More than that, the hosted OCaml toplevel also provided the support of Camlp4, which is another complex beast.

At that point, I got hooked by the power of the JavaScript platform.

The appearances of Node.js and Electron liberated JavaScript from the browser environment. Without a doubt, the JavaScript platform is currently one of the most heavily-invested programming languages.

Languages running on JavaScript

I truly love JavaScript as a dynamic language; despite some warts, it is an enjoyable, dynamic language, especially modern JavaScript (ES6 or later).

However, like most dynamic languages, refactoring is a miserable experience in a large code base, and it is not uncommon to have a JavaScript project contain thousands of lines of code. Even trivial refactoring could result in runtime failures. While such bugs may be easy to fix, they are still a waste of time, not to mention mentally disturbing.

That’s probably why Microsoft, Google and Facebook and other tech companies all started to invest in building type systems on top of JavaScript:

Of these, TypeScript strikes a great balance. It emits extremely readable JavaScript code and provides excellent tooling support. One of its biggest advantages is that it provides a smooth incremental migration path: rename your file from `.js` to `.ts`, add type annotations, and then your code editor can provide more effective auto-completion.

Unfortunately, TypeScript is unsound by design; it is trivial to convert code written in a sound language to an unsound language (like what BuckleScript does), but going the other direction is much more difficult. The type unsoundness means ahead-of-time optimizations are quite challenging.

It is reasonable to expect that using a statically typed language, for example, could provide type soundness and increased opportunities for ahead-of-time optimizations.

So, if you would like a smooth incremental migration path, and want more from static typing, BuckleScript may be the tool for you. It emits readable JavaScript code, does not mangle function and variable names, provides module substitutability (an ES6 module can be literally replaced by an OCaml module), and more:

  • Type soundness and type based optimizations
    Not just type-based refactoring, but also type soundness and type-based optimizations. In BuckleScript, the inferred types are proved to be correct. Therefore, the compiler can take advantage of this information for more aggressive optimizations; see here and here.
  • Lightning fast builds
    Imagine being able to complete clean builds of 60 modules in less than half a second! One BuckleScript user had this to say:

BuckleScript’s compiler is insanely fast, because Bob Zhang (the project lead) has taken to heart the OCaml obsession with performance and routinely tries to optimise away millisecond-level delays. Once you get a taste of that speed (entire project compiled faster than you can blink), you’ll find it difficult to go back to something slower. It’s like getting to use Git after you’ve used Subversion all your life.

I’m really happy that the JavaScript community has found BuckleScript useful and is contributing to its development. While many companies are using it in a wide variety of ways, here are two notable examples of its adoption in the broader JavaScript community:

  • At React Conference 2017 earlier this year, Facebook revealed that OCaml generated using Reason and BuckleScript powers 25 percent of messenger.com.
  • Google’s V8 team used BuckleScript to cross-compile a WebAssembly interpreter into a JavaScript library.

Please do reach out to me on Twitter (@bobzhang1988) and let me know of other noteworthy projects in which you’re using BuckleScript.

Challenges solved in this release!

There are many tools which provide the ability to compile an existing language into JavaScript, and they take advantage of the tools and ecosystem around those languages (which would not exist if the creators had invented a new language). However, when compiling a language into JavaScript, if the runtime semantics of the languages do not match well, the results will be less efficient and less elegant. For example, when compiling Haskell into JavaScript, GHCJS suffers these problems due to Haskell’s lazy evaluation semantics.

In contrast, OCaml’s runtime semantics match very well with JavaScript after performing type erasure. Prior to this release of BuckleScript though, there were still a few semantic mismatches:

First class uncurried calling convention

As a functional language, OCaml only provides curried function calls, and BuckleScript employs fairly advanced optimizations for the curried calling convention. However, the most efficient code is code which does not rely on optimizations.

With this release, we provide first class support for the uncurried calling convention, and all toolchains provided by BuckleScript can understand the uncurried calling convention.

All toolchains provided by BuckleScript can understand the uncurried calling convention.

An additional benefit to this language extension is that it works when using the native platform back-end as well.

API documentation

Now that `ocamldoc` can  understand `[@bs]` natively (instead of printing desugared output), we provide API documentation for the library shipped with BuckleScript. We plan to ship the documentation generator in the next release.

Additional features