OSR » Exceptionless Error Management » Recommendation Candidate 1

In a nutshell a functional value conforming to this recommendation raises only Invalid_argument and Assert_failure, to respectively denote a misuse of the function by the client and an unexpected internal error. If the function may return a value or an error it does so by returning a polymorphic variant with a `Ok case to return the value and an `Error case for errors. If the function returns either a value or no result it uses an option type.

This recommendation says nothing about the usage of exceptions in the implementation of the function. Neither does it say something about clients, if they want to use an exception after an error occured they can define their own exceptions.


A functional value conforms to this recommendation if it guarantees the following points.

  1. Invalid_argument to signal a programming error made by the client.
  2. Assert_failure to signal an unexpected internal error.

Example for (1) : negative character positions in string functions.

val parse_int : string -> [ `Ok of int | `Error  of  [`Syntax | `Overflow ]]
val input_line : in_channel -> string option

A module conforms to this recommendation if each of the functional values of its signature conforms to the recommendation.


Suggestions are not part of the recommendation. They are here to provide guidelines about how and when to apply the recommendation.

In the following situations :

Declare a separate error type for the cases. Example :

type error = [ `First_case | ... ]
val parse : in_channel -> [ `Ok of t | `Error of (int * int) * error ]

In the the following situations :

Do not follow the recommendation and use an exception to report errors.


Usage of the Failure exception in the standard library for unexceptional error cases was acknowledged by Xavier Leroy as being an unsatisfactory legacy solution. In the same discussion Yaron Minsky suggested to use polymorphic variants as a lightweight but explicit mechanism to signal errors. These ideas already appeared in this thread of discussion started by Brian Hurt.

Express yourselves here

The recommendation was updated to allow Assert_failure. -- Daniel

See this link -- Daniel

Ok I refrained to add comments about catching the allowed exceptions. -- Daniel

I agree with this. I added in the suggestion part, cases where the recommendation should not be followed. -- Daniel

Actually, Unix is expected to mimick the libc and have a low-level approach. On the other hand, I would expect those higher-level functions of Pervasives and Sys implementing the same set of features as Unix to also have a higher-level of error-management. -- David Teller

I don't understand your comments about using polymorphic variants where did you get that from ? There's a whole chapter about them in the ocaml manual. -- Daniel

Looking back at the manual again, I guess the warning isn't overly present. It was probably just me reading "weaker type discipline" in the context of "typing is why we use an ML," and inferring that polymorphic variants are best avoided (at least when regular variants can do the job). -- Michael

let safe_div x = function
  | 0. -> `Div_by_zero
  | y -> `Ok (x /. y)

let idiv x y =
  match safe_div (float_of_int x) (float_of_int y) with
  | `Success x -> `Ok x
  | _ -> `Error

This compiles cleanly even with all the warnings...

However in the particular case of Div_by_zero, that's rather a programming error, so a Invalid_argument would be better. -- Nicolas Pouillard

Regarding your example this is why the recommandation says you should return `Value and neither `Success nor `Ok or your own fancy tag. But I agree polymorphic variants are less strict -- Daniel

type ('a,'b) mayFail = Ok of 'a | Error of 'b. -- Till Varoquaux I also prefer using simple things like Either instead of polymorphic variants, when that's sufficient. -- Nicolas Pouillard

The advantage of this recommendation is that we don't need any new type definition in the standard library or external dependency to fullfill it -- Daniel