Last week I was trying to figure out why @bs.open
is necessary to have at all I did a little testing in isolation, and here’s what I found:
- When an OCaml exception is thrown from within a synchronous function, it can be caught by pattern match, as follows:
switch (thingThatThrowsOCaml()) {
| blah => ...
| exception SomeCustomExn(error) => ... here you can do something with the ocaml exception.
}
That works well!
But now take that same code, and put it into a promise chain:
thingThatThrowsAnOCamlExnInsideOfAJSPromise()
->Js.Promise.catch(err => {
switch (err) {
| someJsError => ...branch A
| exception SomeCustomExn(error) => ... branch B
}
})
In that case, branch A is always taken. The ocaml exception is no longer recognized. I have to use @bs.open
on err
instead of just a switch to detect the ocaml exception in that case.
I’ve heard it argued that this is for type safety, but I don’t see (from a developer’s perspective), how putting the switch that matches exception ...
inside of a promise callback would be any less type safe than using it outside of a promise. Branch B in the switch expression would still only match values of that actual type.
This feels like it might be a bit of a hole in Bucklescript to me. Is the logic required to extract OCaml expressions like this without the decorator just too complex?
On a related note, @austindd posted a follow up to my questions in discord: https://discord.com/channels/235176658175262720/235176658175262720/768225829356175390 (thanks, Austin).
The specific case covered there looks useful when I have an exn
already, and I’m trying to get a Js.Exn
out of it, but that’s not what I’m doing here. I usually have to take a Js.Promise.error
and try to turn it into something useful. It’d be amazing if I could use one switch expression to handle the three possible cases of 1) JS Exn, 2) Ocaml exn, or 3) some other value. But currently the code to do that is pretty ugly, not to mention that it requires some obj.magic
since there’s no way to convert a Js.Promise.error
to a Js.Exn
.
Think there’s anything we could do to improve the future ergonomics here, Hongbo and @chenglou? I know that right now my error-handling code is definitely not a pit of success. I usually end up wanting to avoid error handling, since I’m almost always dealing with JS promises, and I almost always have to deal with the difficulties above.
Thanks!