Hacker News new | past | comments | ask | show | jobs | submit login
OCamlScript – a JavaScript back end for OCaml (github.com/bloomberg)
94 points by frutiger on Jan 7, 2016 | hide | past | favorite | 32 comments



This looks like it could be very useful. I've really enjoyed using js_of_ocaml, which supported source maps very nicely, but the value printing was often obscured because types and record field names were erased. This looks like it has much deeper integration with the host JS environment and ecosystem. Great work and I look forward to seeing where this goes.


I'm still wondering why js_of_ocaml couldn't be improved. You yourself did some work towards that, mostly out of the compiler itself.

We have multiple standard libraries, two concurrency library. It has damaged and divided the community significantly. And now two compilers to js ? :/


Small correction: I did not improve js_of_ocaml besides giving feedback (which included feedback about the need to not mangle names).

Before Babel for JS came out, there were tons of different solutions to compiling ES6 features into ES5, and the decision about which toolchain to use would fatigue newcomers to the community. But it was the fact that the community was relatively accepting of new spinoffs that Babel was able to gain momentum, and increase its quality to the point where it is the de factor tool that everyone uses - and it's really good.

As a consumer of the compiler, I don't necessarily consider multiple options a bad thing as long as something of really high quality emerges. (Although I can see how for something like an Async library (that introduces incompatibilities between dependencies) that would be particularly frustrating to have too many options)

It looks like OCamlScript used some good ideas from js_of_ocaml. Maybe js_of_ocaml can end up sharing some of the good ideas from OCamlScript so that it can also have very readable/debugable code and ecosystem integration?


Drup, Ah, yes - CommonML does indeed have built in support for js_of_ocaml.

And I think you have valid points. I'm curious though, since both js_of_ocaml have seamless interop with JS (seamless in terms of memory model), couldn't the two have seamless interop between each other by going through JS bindings?

I'm curious, do you think it's possible or practical to create an OCaml to JS compiler that has the strengths of both approaches?


It doesn't seem that ocamlscript and js_of_ocaml are using the same memory representation for OCaml values, so that's a first issue.

At least for the integration between the js world and the ocaml world, I do believe it is possible. yes. For readability of the js produced, I really can't tell. It's probably pretty easy to improve js_of_ocaml on that though, given the current state. :)


Drup:

Also, if it wasn't abundantly clear (to you or others) - I believe js_of_ocaml to be perhaps the best systems language compile-to-js toolchain that I've ever discovered (and I've looked extensively for others) - so I hope you can fully appreciate just how valuable it continues to be, to me personally and many others.

I have a question about your comment: "It's probably pretty easy to improve js_of_ocaml on that though, given the current state."

Would this also require patching the compiler to preserve record field names and avoid name mangling in general?

And I have a question about your comment on reddit which implies that maintaining a backend would be difficult to sustain: Do you believe that a seamlessly debuggable JavaScript backend, could generate the necessary amount of attention required to sustain such a backend, given how much more widely accessible end-end OCaml development would become as a result of its existence?


Drup, By the way, I really have appreciated the absolute simplicity of js_of_ocaml - it's pretty great how you can just take any byte code file and run it in any JS engine with great performance - it's amazing really. I really love how js_of_ocaml does dead code elimination, and inlining among other features.

It seems like the primary difference is that the goals of js_of_ocaml gravitate more towards taking an app/library that had already been fully tested/debugged in OCaml and then running that thing in the browser with some nice debugging facilities that let you see the source code and kind of step through in the more rare event that something goes wrong.

I can't speak for this new approach here, but it seems to be more focused on using the JS target as the core development workflow for rapid iteration. I can see why that's appealing. Everyone knows how to use the browser debugger, and JS is one of most ubiquitous byte code formats ever. Running your OCaml app in the browser also gives you all kinds of really great timing and memory profiling tools that help you detect leaks (that even tells you something about the nature of your program when compiling OCaml to machine code).

Obviously, I wish there was a single toolchain that could actually do both though - a toolchain that you could use to get very JS-friendly code generation so the debugging/value printing/console inspection works just like it does in JS, but then would also let you do a js_of_ocaml style compilation based purely on an OCaml byte code object file (edit: or some kind of representation of the whole program) which would be free to remove and obscure record field names if it so chose.

(BTW: The difference in object representation (record field names are not obscured) seems to be the very thing that makes the values inspectable in the browser. Maybe there are some of OCamlScript's compiler patches that could be accepted in upstream ocaml so that the same can be achieved with js_of_ocaml?).


I was actually talking about your work for CommonML[1], which I count as improvements to the "js_of_ocaml ecosystem". ;)

My issue here is that both are strictly incompatible and that you can't write FFI to a library for both.

[1]: https://github.com/jordwalke/CommonML


Author here, just created a new account : ). I think ocamlscript is complementary to js_of_ocaml, actually it is inspired from js_of_ocaml. For those who like to write ocaml only application, js_of_ocaml is perfect, ocamlscript is designed to help easier integration with existing javascript system.

Design goals here: http://bloomberg.github.io/ocamlscript/


In the (nice) immutable map example on that page, a reference cell is used & updated each time something is added to the map. How would the JS output differ if you built the map using a fold or similar, without any refs?


Before that, I'd ask if the implementation of OCaml's map is at all similar to the implementation of Immutable.js's Map. Different internal data structures/algorithms are probably the most likely explanation for any difference. Still, it's nice to see a benchmark that shows how OCaml compiled to JS is competitive in performance, even when compared to a very popular library that is known for performing well.


Also a fair point, and I take your implication that the effect of a change to the outer loop syntax would probably be lost in the noise. It just struck me that using ref cells and loops feels like a concession to writing Javascript-style code in the first place (I grant in this particular case it makes the code more obvious) and I wondered how much difference it actually makes. Is the compiler able to flatten a fold into a similar loop? Or do you get a readable fold call in the JS code and, if so, is it much slower? Or neither?


List.fold_left is compiled into a while loop in ocamlscript. The main reason that I used for loop is that the generated code is the same as hand written js, so the comparison is more reasonable

Edit: I am a practical programmer, I am in favor of both for loop and recursion as long as it is readable


That is how you justify the project, and it makes sense, when you look at it with a microscope.

But my remark still stand: we now have two compilers to js, their API/FFI is not the same, so you can't factorize work, and the integration work could be made on js_of_ocaml too (see alain frisch's project).


Hi Drup,

I'd be curious to hear about the work that Alain is doing. Do you have a link?



actually we have great relationship with Lexifi, and we did exchange some ideas about ocamlscript before, I think mostly we are on the same page, there is enough room for two compilers :-)


Its good to see ocaml->js back to life. Have you considered supporting TCO or arbitrarily deep stack? I'm just curious how often could we reuse ocaml libraries with just tail call to loop conversion.


self tail call is supported. mutual recursive tailcall can be done partially, but there is not a strong guarantee


I would say the main problem with the OCaml community is it's too small. More projects are welcome imo, even if it inevitably means some duplication of effort. After all js_of_ocaml is free to take some of the more desirable features.


Hi, thanks for your interest in it.

This project has been released to exchange some ideas and collect feedback from the OCaml and JavaScript communities. It is still in an very early stage and more like research projects though we already had some good results.

Note that ocamlscript is inspired from typescript and js_of_ocaml, we like the readability of typescript generated js code, while don't want to loose the expressivity of a powerful langauge, ocaml, here in particular.

The main difference from js_of_ocaml is that js_of_ocaml maps the whole bytecode program into a js file while ocamlscript maps an ocaml module to es6 module.

Indeed, there is some difference in the runtime representation between js_of_ocaml and ocaml, for example, ocamlscript uses js string and array for ocaml string and arrray(we do this since we want an optimal js output at the price of a bit runtime incompability), this may make interaction between js_of_ocaml and ocaml a bit harder, but that's exactly why we made an early release to hear what other people may think. js_of_ocaml is an excellent project and we learned a lot from it and will seek some collaborations to share some workload.


Question for hongboz and Drup about F-lambda:

OCamlScript does some cross-module optimization it seems. That's really cool, and js_of_ocaml does several optimizations as well, but for both approaches, it seems we'll not be able to take advantage of all really great f-lambda optimizations to come because they happen at a compiler stage after OCamlScript and js_of_ocaml have already intercepted their intermediate representations. Do you (or Drup) have thoughts on that?


It would be great to see a list of known/anticipated compatibility issues. For example, I notice that when compiling `String.set` with OCamlScript, the generated JS ends up trying to set/mutate a character in the JS string, which has no effect because JS strings are immutable. (I'll file a github issue). I imagine there will be several small issues like this and it would be good to get a sense for how much work it would be to solve that long tail of compatibility work. In the process, I think the community can help determine if this approach could ever practically match the near-perfect level of compatibility that js_of_ocaml has achieved via byte code compilation - and whether or not it matters. To me, compatibility is very important, but so is debugability. It might be clear that it's okay to compromise the readability of OcamlScript in order to achieve more compatibility without compromising debugability (for example, using a `new MLString("xyz")` wrapper that uses a JS `String` by default for performance, but then swaps it out upon any mutation. (Or perhaps you can limit it to programs that have disabled string mutations in later versions of OCaml).

The good news is that if you can achieve perfect compatibility with this approach, then I believe that runtime performance becomes less of a concern and OCamlScript's job gets a lot easier. This is because, if you've achieved perfect compatibility, you can easily compile your project with another toolchain such as js_of_ocaml, that has equal compatibility, but (in this hypothetical scenario) had chosen to focus more on performance instead of debugability - without changing anything in your program.

This would free you up to not have to worry about applying any optimizations in this readable/debuggable mode - you get to focus entirely on whatever makes the development flow faster/easier. (You'd probably still want tail call optimization because order of memory usage could be considered a key part of compatibility).

Similarly, I wonder if the existence of a fully compatible, (hypothetically) slow runtime performance, but perfectly debugable compiler backend, would then free up js_of_ocaml from some of the constraints/work that is required to make their code output reasonably simple/debuggable. Does the existence of a fully compatible OCamlScript mean that js_of_ocaml's job gets easier?

I'm excited to discuss how the two projects could potentially become an asset to each other.

edit: I started a discussion on Github here: https://github.com/bloomberg/ocamlscript/issues/12


Not to be confused with the other OCamlScript [1]. Also, other than the naming overlap, is there any reason why this hasn't been made available as an OPAM package? Having to manually patch, compile, and install is a bit of an inconvenience when the `opam switch` infrastructure already exists. Is it just a matter of time before it's added to OPAM or are there simply no intentions of adding it to the repositories? [1] - http://mjambon.com/ocamlscript.html


I made github issues to discuss the name collision as well as allowing the compiler patches to be applied via an OPAM switch.


Interesting to see many type safe functional languages compiling to javascript. Elm is another such project being a haskell-like type safe language which compiles to JS/HTML/CSS.


PureScript is another one worth a look


Other compilers for ML-family languages to Javascript:

SMLtoJS (whose site at http://www.smlserver.org/smltojs/ perhaps ironically seems to be down at the moment), which compiles the full Standard ML language (though not the full Basis library)

Yetiscript (https://www.npmjs.com/package/yetiscript) which compiles (a very close approximation of) the Yeti language (http://mth.github.io/yeti/)

Looks like there are some F# options as well, though I haven't tried any and I don't know what the relationship between e.g. Websharper and Funscript is.

Any others?


This is great, idea of mapping a module to es6 module makes sense.


what is it about js_of_ocaml that made this worth doing?


The design goals section of the README makes that pretty clear. js_of_ocaml produces pretty opaque JS (in my experience) that doesn't make much use of modern features like modules.


Yes please.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: