Reading — step 1 of 7
Learn
OCaml has exceptions for genuinely exceptional conditions. Idiomatic OCaml prefers option / result for expected failures, exceptions for the unexpected.
Defining exceptions
exception Not_found_in_db
exception Invalid_input of string
exception Bad_age of int
exception Name of payload-type — like a variant constructor, but for the exception type.
Throwing — raise
let validate s =
if s = "" then raise (Invalid_input "empty")
else s
let head = function
| [] -> raise (Failure "empty list")
| x :: _ -> x
raise exn throws. There's also failwith "msg" (raises Failure) and invalid_arg "msg" (raises Invalid_argument) — short forms for common cases.
Catching — try/with
try
let n = int_of_string (read_line ()) in
Printf.printf "got %d\n" n
with
| Failure msg -> Printf.printf "parse failed: %s\n" msg
| End_of_file -> print_endline "no input"
try EXPR with PATTERN -> HANDLER | PATTERN -> HANDLER- Pattern-matches on the exception type
- Re-raise with
raise:with e -> log e; raise e
Common stdlib exceptions
Failure msg— generic; raised byfailwithInvalid_argument msg— bad input; raised byinvalid_argNot_found— search failed (List.find, Map.find, etc.)Division_by_zero— int division by zero (note: float div by zero gives infinity)End_of_file— input stream endedMatch_failure— non-exhaustive match on input it doesn't coverStack_overflow— recursion too deep
Exceptions vs option/result
(* throwing — caller MUST handle: *)
let div a b =
if b = 0 then raise Division_by_zero
else a / b
(* option — caller pattern-matches: *)
let div_opt a b =
if b = 0 then None
else Some (a / b)
(* result — caller pattern-matches with reason: *)
let div_res a b =
if b = 0 then Error "div-by-zero"
else Ok (a / b)
Modern style: prefer option / result for expected failures. Exceptions for cases where the program shouldn't continue (genuinely exceptional, unrecoverable, or programmer-error situations).
try-as-expression
let n =
try int_of_string s
with Failure _ -> 0
try is an expression — evaluates to the body's value or the matching handler's. Useful for inline default-on-error.
Performance — exceptions are slow
Throwing in OCaml allocates and walks the stack. For control flow on hot paths, prefer option / result.
There's a special form raise_notrace that skips the stack trace (slightly faster):
raise_notrace Not_found
Use for performance-critical exception throwing where you don't need debug info.
Common mistakes
- Using exceptions for expected failures — slower and obscures intent. Use option/result.
- Catching all exceptions —
with _ -> ...swallows everything including programmer errors. Catch specific types. - Forgetting to re-raise —
with e -> log_error ()silences the exception. Addraise eif you want it to propagate. - Not handling Match_failure / Not_found from library calls — most stdlib functions document what they throw; check.
- Throwing strings —
raise "oops"is a type error. Use a defined exception or Failure / Invalid_argument.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…