Exceptions and the Option Type
Exception declarations
Exceptions are declared like constructors of a special built-in type exn:
exception Failure
exception NoChange of int
Failureis a simple exception carrying no data.NoChange 6carries an integer explaining which amount could not be changed.
Each exception declaration introduces a distinct sort of error that can be caught separately.
Raising and handling
raiseabandons the current computation and propagates the exception upward.try ... withcatches exceptions and attempts an alternative computation.
try
print_endline "pre exception";
raise (NoChange 1);
print_endline "post exception";
with
| NoChange _ -> print_endline "handled a NoChange exception"
The output is pre exception followed by handled a NoChange exception. The code after raise is never reached. The handler matches exceptions using pattern matching, and only the most recently entered handler that matches is invoked.
Dynamic matching
Exception handlers are resolved dynamically (at runtime). This contrasts with how OCaml resolves variable bindings, which happens statically (at compile time). A function can raise an exception deep in a call chain, and the handler might be in a completely different part of the program.
Comparison with Java
OCaml’s exceptions have no checked exception mechanism: nothing in a function’s type indicates which exceptions it might raise. In Java, checked exceptions must be declared in the method signature. This is a trade-off: OCaml gives more flexibility at the cost of less static documentation of failure modes.
The option type
An alternative to exceptions is the option type:
type 'a option = None | Some of 'a
| Mechanism | Success | Failure |
|---|---|---|
| Exceptions | Normal return | raise |
| Option type | Some x | None |
The option type makes failure explicit in the type: a function returning 'a option clearly signals that it may fail. The drawback is that every caller must check for None, which can clutter the code.
When to use each
- Exceptions: when failure is truly exceptional and the normal control flow should not be littered with error checks.
- Option: when failure is a routine outcome that callers should handle explicitly.