I haven’t yet had the chance to read the blog post, but I’ve been following the ensuing discussion here (Hi Louis!). Regarding the comments about the handling of “uncatchable” exceptions, I wanted to bring up 3 examples from commonly used libraries:
Rresult.R.trap_exn
(latest = 0.7.0):
let trap_exn f v = try Ok (f v) with
| e ->
let bt = Printexc.get_raw_backtrace () in
Error (`Exn_trap (e, bt))
Base.Or_error.try_with
(latest = v0.17.0):
let try_with ?(backtrace = false) f =
try Ok (f ()) with
| exn -> Error (Error.of_exn exn ?backtrace:(if backtrace then Some `Get else None))
;;
Stdlib.Fun.protect
(latest = 5.2)
let protect ~(finally : unit -> unit) work =
let finally_no_exn () =
try finally () with e ->
let bt = Printexc.get_raw_backtrace () in
Printexc.raise_with_backtrace (Finally_raised e) bt
in
match work () with
| result -> finally_no_exn () ; result
| exception work_exn ->
let work_bt = Printexc.get_raw_backtrace () in
finally_no_exn () ;
Printexc.raise_with_backtrace work_exn work_bt
I haven’t delved deeply into these examples, but at first glance, it seems like all three might exhibit the characteristic of catching all exceptions, including those that are considered “uncatchable” as discussed here. Do you concur? Is this really an issue in practice?
Possibly related discussions:
By the way, this may be off-topic for now, but I’m curious about how these exceptions would interact with an OCaml’s type system that gained the ability to express the exceptions a function can raise as part of its type. What would be the status of exceptions that are designed not to be caught?