Js_of_ocaml -> calling the translated javascript

I’m unsure how to reference or call the generated javascript. It’s basically gibberish.

Say my ocaml is:

let rec sort = function
   | [] -> []
   | x :: l -> insert x (sort l)
and insert elem = function
   | [] -> [elem]
   | x :: l -> if elem < x then elem :: x :: l
               else x :: insert elem l;;

how would I call the translated javascript function?:

// something like this
// function sort(arr) {}
sort([3,1,2])

Js_of_ocaml is not really designed to be callable from JavaScript. Its output is a low-level ‘assembly-like’ version of JavaScript. This output is meant to be the final application that runs in the browser, not a library that’s called by other JavaScript consumers.

1 Like

The same way you would in a standard OCaml program:

let () =
  ignore (sort [3,1,2])

Now, for a less toy example, it would depend on what the target is. For example, if the code is meant to be embedded in a webpage, the let () = ... code would perhaps take care of registering a callback on an onclick event of a button. Again, because everything is performed on the OCaml side, whether the resulting Javascript is gibberish does not matter.

so, say I was expecting to have some javascript function:

function sort(arr) {}

There’s no way to call the translated ocaml?

From JavaScript? No, not that I know of.

But from another OCaml source file in the same project? That’s trivial, just call it like a normal cross-module call.

1 Like

You can definitely call Js_of_OCaml code from JavaScript. You just need to wrap it in an exported JS module.
See Export OCaml code to JavaScript.

I haven’t checked, but you will probably have to add conversions from JS arrays to OCaml lists in your OCaml code.

4 Likes

As other have mentioned that is perfectly possible.

But if the function you export is acting on OCaml values you will have to write a stub to convert from the JavaScript types you’d find natural to provide to the OCaml values your OCaml function expects.

In addition to @mnxn’s reference this is also lightly touched on in Brr's FFI cookbook here.

4 Likes

My mistake. Totally forgot about the export feature.

Thanks so much for your help.

I’m hitting a few potholes along the way. I’m unable to run the example at http://ocsigen.org/js_of_ocaml/dev/manual/rev-bindings:

$ cat math.ml
let _ =
  Js.export_all
    (object%js
      method add x y = x +. y
      method abs x = abs_float x
      val zero = 0.
     end)
$ ocamlfind ocamlc -verbose \
  -package js_of_ocaml -package js_of_ocaml-ppx \
  -linkpkg math.ml -o math.byte
Effective set of compiler predicates: pkg_bytes,pkg_uchar,pkg_js_of_ocaml,pkg_js_of_ocaml-ppx,autolink,byte
+ ocamlc.opt -verbose -o math.byte -I /home/g/.opam/default/lib/bytes -I /home/g/.opam/default/lib/uchar -I /home/g/.opam/default/lib/js_of_ocaml -I /home/g/.opam/default/lib/js_of_ocaml-ppx -ppx "/home/g/.opam/default/lib/js_of_ocaml-ppx/./ppx.exe --as-ppx" /home/g/.opam/default/lib/js_of_ocaml/js_of_ocaml.cma math.ml
+ /home/g/.opam/default/lib/js_of_ocaml-ppx/./ppx.exe --as-ppx '/tmp/camlppx16679a' '/tmp/camlppx8a9bc9'
File "math.ml", line 2, characters 2-15:
2 |   Js.export_all
      ^^^^^^^^^^^^^
Error: Unbound module Js
ocamlc.opt returned with exit code 2
$ ocaml -version
The OCaml toplevel, version 4.11.1
$ opam --version
2.0.8
$ ocamlc -version
4.11.1
$ uname -a
Linux manjaro 5.9.16-1-MANJARO #1 SMP PREEMPT Mon Dec 21 22:00:46 UTC 2020 x86_64 GNU/Linux

I changed math.ml in the following way to resolve this:

(*math.ml*)
-
+ open Js_of_ocaml

let _ =
  Js.export_all
    (object%js
      method add x y = x +. y
      method abs x = abs_float x
      val zero = 0.
     end)
// index.js
var math = require('./math.js');
console.log(math.add(2,3))

It now compiles:

$ node index.js
5

I have tried to do something similar some time ago for timere, in case you want a slightly more complex example

(I guess the main takeaway would be if you want to expose a Seq.t, it’s easier to make it into a generator function, and store the Seq.t in a ref, see method resolve)

1 Like