What is the difference between a bool
and a bool Js.t
, and how do I convert between the two ?
In js_of_ocaml, every javascript elements are encoded inside a phantom type ('a Js.t
), which allow to have a different representation for each of them. (see the table in the js_of_ocaml documentation )
This type is here to declare that an element belongs to the javascript world and cannot be used with the usual functions from the standard library.
As the type does not have contructor, you cannot create Js.t
value directly, but the module Js
provide some functions in order to switch from the OCaml type to javascript and vice-versa.
(I don’t know why, but the css is broken, the documentation is still readable)
-
This table is outdated as of jsoo 5.1.0 right? Since we now have OCaml string == JS string
-
Here is what I struggle with. Instead of Js.t, consider option / array / list
Given v: t, we an do: Some(t), [t], [| t |] , which allows us to do
t → t opt, t → t list, t → t array
For the other direction, we can write functions that either succeed or throw an exception.
- I understand the individual words but not the concept of:
What is the relation of the 'a
in 'a
and 'a Js.t
if we do not have auto converions in either direction ?
That’s incorrect every javascript value 'a Js.t
has the same representation: it’s a JavaScript object. The phantom type 'a
is just a trick to track what the objects offers to call on it, you can put whatever you want here. It’s a way of structurally typing JavaScript objects (a bad idea if you ask me).
Thanks dbuenzli your are right. I thought that some gadt magic where hidden behind in order to give a different representation.
For zeroexcuse, the point is that Js_of_ocaml is building a javascript code from the ocaml bytecode, and during the compilation all the types disapear. The bytecode->javascript compiler just get a bytecode without any information if the element is an option, a list or a tuple, but get the confirmation that all this code typechecks.
This said, we do not want automatic conversion, sometimes we are linking an external js library which requires 'a Js.t
elements, and sometimes we want to call some ocaml code which returns a pure Ocaml element.
This does not give much solution, either you hide the javascript type into an abstract element (like dbuenzli did in Brr, for example Jstr.t is the equivalent of js_string Js.t
), or you ensure that everything typechecks using another trick (but this is another discussion I do not want to be dragged into it )
Is the following an accurate mental model:
'a Js.t
is nothing more than JS object that pretty promises to have some properties
What is the point of the pretty promise ? So that for JS FFI functions, instead of writing:
js object -> js object -> js object
we can do something slightly more type safe, il.e.
'a Js.t -> 'b Js.t -> 'c Js.t
Is there any other use / utility of 'a Js.t
?
That’s it. And the properties are encoded into an OCaml object type.
It’s a nice trick, but not very ergonomic in practice – like phantom types often are. You can read more on the reasons that lead me to brr
’s approach in brr’s FFI manual foreword.
This is still true as of 5.1. The only difference is that now OCaml strings are encoded as UTF-8 strings in Javascript. The difference becomes clear when dealing with multi-byte codepoints:
Javascript strings are UTF-16, so when the UTF-8 encoded string 0xF0 0x9F 0x98 0x8A
is dumped into JS, the result above is produced.
That’s not exactly what’s happening :–)
An OCaml string
is a sequence of arbitrary bytes. In the new representation, that sequence of bytes (not necessarily UTF-8 valid) is encoded into a JavaScript UTF-16 string by using the unicode characters in the range U+0000 to U+00FF – a so called JavaScript binary string (this used to be documented on MDN but it seems someone decided to kill the terminology, which is silly because it means there must be a broken link in brr
’s doc and some JavaScript functions work with these strings e.g. atob
and bota
. Here’s the archived page about them)
Since we are there, one nice orthogonal change that happened in js_of_ocaml 5 regarding strings is that you can now define JavaScript string literals directly from your UTF-8 encoded OCaml sources. That is in some static scenarios js_of_ocaml
spots the conversion from a literal OCaml string interpreted as UTF-8 to a JavaScript (UTF-16) string and does it at compile time instead, resulting in a JavaScript string literal in the produced JavaScript (rather than, previously, a byte escaped UTF-8 sequence to be converted to UTF-16 at runtime)
So now, when you want a “literal” JavaScript string containing , you can write (in brr
)
let ocaml = Jstr.v "🐫"
to get it without any conversion costs at runtime (more details in this issue):
echo 'let ocaml = Jstr.v "🐫"' > test.ml
ocamlfind ocamlc -g -linkall -linkpkg -package brr test.ml
js_of_ocaml --linkall a.out -o test.js
grep '🐫' test.js
[...](3821,[0,"🐫"],"Test");fb(0);r(3822,[0],"Std_exit");return}(globalThis));
.
Ah, thanks @dbuenzli. I think what you’re saying is what I was trying to convey, but probably with poor wording. Thanks for the clarification
@dbuenzli : I’m doing research on Brr. Can you tell me how Note/frp plays into this? Is it meant to be an alternative to react ?
I suppose you meant react as in JavaScript (Note
is an alternative to that other react, explanations about their relationship here).
Brr
just provides an ergonomic JavaScript FFI and bindings to established and forward looking browser APIs. The Note
stuff you find in Brr
is here by accident (used by private code of mine) and will be tweaked and moved away to an optional dependency of Note
at some point.
Regarding whether Note/frp is an alternative to JavaScript react, I never understood what was so great about JavaScript react/elm architecture/whatever hype du moment so I can’t tell you but Note/frp is definitively a good way to program user interfaces in a sane and compositional way. In case you missed it there’s a todomvc example here.
@dbuenzli : Apologies if this comes off as pedantic.
I’m working through the test_midi.ml example, and am looking at your usage of: Result_syntax (brr.Fut.Result_syntax)
Question: Why does Brr (a JS binding library) have its own Future/Result extension syntax? Intuitively, I’d expect there to be a standard approach to this in some foundational / core OCaml library. A typed JS/DOM/Web library seems a weird place to add this.
Therefore, I’m clearly not seeing something important – what is the driving motivation behind Fut/Result_syntax ?
Also, is this related to async JS ? By the keyword Fut
, I’m expecting something to do with JS promises, and thus JS async, but I’m not seeing it in the test_midi.ml example.
Because a JavaScript binding library needs to deal with JavaScript promises and Promise.resolve
can’t be typed in OCaml see this comment in fut.ml
.