Exceptions

Keeps the success branch out of the try scope (preserves tail calls).

17.1 Built-in exceptions

List.find, Hashtbl.find, String.index Invalid_argument of string bad args, out-of-bounds Failure of string failwith, int_of_string Sys_error of string OS-level file errors free for you to use Stack_overflow, Out_of_memory assert false non-exhaustive match at runtime

17.2 Raising

failwith "something went wrong"         (* raise (Failure "...") *)
invalid_arg "negative input"            (* raise (Invalid_argument "...") *)
raise Not_found
assert (x >= 0)

17.3 Defining exceptions

exception Insufficient_funds of float
exception Parse_error of { line : int; msg : string }

17.4 Handling

let safe_div a b =
  try a / b with
  | Division_by_zero -> 0

let withdraw balance amount =
  if amount > balance then raise (Insufficient_funds (amount -. balance))
  else balance -. amount

let () =
  try ignore (withdraw 100. 150.) with
  | Insufficient_funds short -> Printf.printf "Short by %.2f\n" short
  | e -> Printf.printf "Other: %s\n" (Printexc.to_string e)

17.5 Exceptions in match

Keeps the success branch out of the try scope (preserves tail calls).

match List.assoc key table with
| v -> use v
| exception Not_found -> default

17.6 Cleanup: Fun.protect

Also In_channel.with_open_text (see §19).

let with_file path f =
  let ic = open_in path in
  Fun.protect ~finally:(fun () -> close_in ic) (fun () -> f ic)

17.7 Backtraces

let () = Printexc.record_backtrace true
(* or env var OCAMLRUNPARAM=b *)
try risky () with e ->
  prerr_endline (Printexc.to_string e);
  Printexc.print_backtrace stderr;
  raise e    (* or Printexc.raise_with_backtrace e bt *)

17.8 Using exceptions for early exit

let find_index p arr =
  let exception Found of int in       (* local exception *)
  try
    Array.iteri (fun i x -> if p x then raise (Found i)) arr; None
  with Found i -> Some i