JS_of_OCaml vs Bucklescript

It’s not true that jsoo preserve all undefined behavior(or unsafe subset), maybe it covers some subset where core happens to used.
JSOO is an amazing piece of software that I have full respect(and I still use it), but we also put great effort to make OCaml accessible to average JS dev. Actually why I made BuckleScript is because I failed to sell JSOO to my last employer, it is very hard to sell it in a company whose codebase is not mostly OCaml.

Edit: why it is hard to sell is that JSOO needs developers to go all in on the OCaml technology(which is great but hard to convince your manager) while BuckleScript provides an incremental migration path. It is an amazing story that Janestreet adopted OCaml in most of his codebase, but it is not the case for most other companies, sadly.

Edit: I understand that BuckleScript may not appeal to some hard core OCamler’s taste, but it is a great addition to the OCaml ecosystem, there is almost no competition between BuckleScript and JS_of_OCaml, one is targeted to audience who cared about JS and incremental migration is a must while the other is targeted to audience who already got engaged in OCaml. It is something that we really should be proud of that we have two high production quality JS compilers, I do not know of a second language that has such luxury.


I think it’s better than that indicates. It of course doesn’t capture everything, but it gets a surprisingly large subset. Indeed, while I’m sure they exist, I can’t think of a principled use of Obj.magic that fails under jsoo. Do you have any examples in mind?

I admit that at first I didn’t see the point at all, but it does seem that Bucklescript fits in much more easily for people with a largely JavaScript toolchain. I think the only unfortunate thing about the jsoo/bucklescript split is that bindings now have to choose which one they support. It would be great if we could move towards tools that could support both. Maybe gen_js_api could be come such a tool…

That’s of course true, but it’s worth noting that you don’t have to have a complete OCaml toolchain to use jsoo effectively. You can definitely call ordinary JavaScript from jsoo code, and I believe the reverse is pretty easy as well. It seems like the key advantage of Bucklescript is that it generates readable JavaScript, which jsoo definitely doesn’t!


Side note. I think it’s quite unfortunate that Coq generates that sort of code. I’m not sure I understand why it’s necessary, but I’ve never understood the internals of extraction very well.

It would be great to have a more thorough comparison between the two tools. Having used JSOO as part of Eliom and having vaguely observed Bucklescript from afar in Reason, I’d love to know what the actual differences are. I know BS is trying to use native JS types as much as possible, which isn’t the case in JSOO, and that BS’s conversion starts post-typechecker, while JSOO converts Lambda AST. Is FFI easier in BS?

Also, @bobzhang, it was really disheartening for me to learn that BS added the new |. operator. It’s syntactic sugar that makes it very hard to convert BS to OCaml code compatible with the rest of the ecosystem – you’d essentially have to use camlp4. I think these things need to be weighed very heavily before they’re added, as they slowly turn BS into an incompatible fork of OCaml.

BS’s conversion starts post-typechecker, while JSOO converts Lambda AST

AFAIU, BS’s conversion indeed starts post-typechecker using the Lambda intermediate representation as source (which is internal to the compiler). Jsoo starts from the bytecode produced by ocamlc (a bit later in the pipeline).
This is why js_of_ocaml doesn’t need to exist as a compiler fork, and is a lot less tightly bound to the compiler’s implementation (since ocaml’s bytecode is quite stable).

The addition of the |. and the direction of Belt and Reason are indeed heading towards a fork which is very concerning. It’s unfortunate that I can’t build React apps in OCaml using the OCaml ecosystem.

It is a normal PPX(provided by the compiler and a flag to turn it off).

The belt library is a highly optimized library for JS backend, it is up to the user decide to use it or not, note currently BuckleScript already did a very good job with regard to the added JS size, belt tried to deliver the optimal experience for large scale UI productions.

Here is a tldr story that explained why we introduced belt, people told me that they can not use ocaml stdlib map, since the internal monitor tools showed it brings more than 10K bytes in the JS payload, after we introduced belt, the performance is better, and the added size is reduced to 1K bytes, and people are happy about it.


Think about the representation of float. It has quite different representations

I think this is an approach which prevents all improvements in writing code. I have a legacy CoffeeScript library and it generates some pretty readable JavaScript code, to the point where I get pull requests that modify the JavaScript code. It got a little bit better since the CoffeeScript compiler added a note that the generated source is explicitly not the the canonical source code. If the generated code is the canonical hackable source, what is even the point of using a compiler if you can only do the compilation step once before you start editing the generated code, thus a second compilation would just erase all your changes.

The only times I have found the readable output of CoffeeScript useful is to learn how its syntax works, because it was easier to write something and see what it compiles to instead of actually learning the syntax properly. Which probably speaks more about the ambiguous syntax of CoffeeScript than anything else.

With OCaml it is still pretty alright, because the semantics are still pretty close to JavaScript, so generating readable source code is attainable. But if you start to use compilers for PureScript or Eta I could imagine that e.g. compiling lazy semantics would lead to JavaScript code that is everything but readable, because you sort-of implement your own semantics on top of JavaScript.

What worries me is that BuckleScript is still stuck on 4.02.1, a version that seems to be on its way out in the general OCaml community where it is not uncommon to see 4.03 as minimal version, so over time less and less existing code will be compatible. And despite announcements of rebasing to newer versions, so far to my knowledge this hasn’t happened any single time. It would be required to be done either pretty often, like on every new upsteam release or included in the mainline compiler. Rebasing is hard, which is why I suppose multicore will be merged, to keep it from bitrotting. I fear we are seeing a fork that might go the same way as MetaOCaml or JoCaml before.

So in my opinion BuckleScript is more an OCaml-like language, possibly with a JavaScript-like syntax (Reason) aimed at the same market as Elm, not aimed at OCaml developers who would like to avoid having to write JavaScript.


So in my opinion BuckleScript is more an OCaml-like language, possibly with a JavaScript-like syntax (Reason) aimed at the same market as Elm, not aimed at OCaml developers who would like to avoid having to write JavaScript.

Keep spreading such FUD makes me feel really sad, we are working really hard to bring OCaml to more commercial use cases, BuckleScript definitely aims to be 100% honest to OCaml language semantics and its type system.
Js_of_Ocaml has been around quite a long before BuckleScript’s existence, if you think js_of_ocaml is the right approach to attract more audience, it should have already happened. I don’t think there is competition between each other, we are solely bringing more people.


To me, the unfortunate part is that BuckleScript is maintained outside of the mainline of OCaml as a fork. If it was maintained inside the same infrastructure and always up to date with the latest release, it would be less problematic to me for there to be two JS backends.

Having worked on a small BuckleScript/ReasonReact app full time for two weeks, my experience is mixed.

On the one hand, the experience with BuckleScript is quite smooth. The build system, the standard library (Belt), built-in syntax extensions, libraries like ReasonReact, all work well together and present a compelling package. They are built with a lot of care and attention to details.

On the other hand, BuckleScript makes it very hard to reuse any existing code. (Not a lot of people have the luxury of having this problem, though!) You can’t just use an opam package; you need to convert it to an NPM package first. Can’t use your favorite ppx. Can’t share async code between native and JS.

While with js_of_ocaml you can take any package from opam, use any ppx, use Lwt on both client and server. This is very compelling for me.

My impression is that, while BuckleScript is faithful to OCaml, the language, it forks the OCaml ecosystem. And that’s not necessarily a bad thing. Existing OCaml ecosystem has a huge survivorship bias. Just compare what is being worked on in the “new world” (BuckleScript/Reason) and the “old world”. The old world is addressing the issues of the existing OCaml users, big and small. While the new world is focused users, who are yet to be OCaml developers. The new world is working at the beginning of the acquisition funnel, while the old world—with the end of it.

So I plan to stick to the old world myself but will keep promoting both the old-world as well as BuckleScript, Reason, and Elm—depending on who I talk to.


An argument that may be made (I don’t know what kind of mind mapping these readable outputs gives in practice) is that you might get reasonably readable information when you enter the JavaScript debugger.

While I was in totally in awe when I called Js.debugger () and found the OCaml sources of my js_of_ocaml compiled program available right here for stepping through, the abstraction was quickly leaking.

For example the representation of OCaml variables makes little sense unless you know a bit about the way js_of_ocaml represents ocaml values; see @vouillon’s paper.

I personally don’t mind that much since my debugging tool of choice remains printf which works perfectly in js_of_ocaml, but then I wouldn’t mind higher level luxury.