# Exception vs Result

**URL:** <https://discuss.ocaml.org/t/exception-vs-result/6931>\
**Category:** Learning\
**Tags:** exceptions\
**Created:** [December 7, 2020, 7:38pm UTC](https://discuss.ocaml.org/t/exception-vs-result/6931 "2020-12-07T19:38:10Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![cemerick](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/cemerick/32/1383_2.png) [@cemerick](https://discuss.ocaml.org/u/cemerick)\
**Post date:** [December 7, 2020, 7:38pm UTC](https://discuss.ocaml.org/t/exception-vs-result/6931/1 "2020-12-07T19:38:10Z")

</div>

Last week, @BikalGurung blogged [On Effectiveness of Exceptions in OCaml](https://lemaetech.co.uk/articles/exceptions.html), in part as a follow-up to [his announcement of his parser combinator library](https://discuss.ocaml.org/t/ann-reparse-2-0-0/6868) [reparse](https://github.com/lemaetech/reparse/), which eschews `Result`-based error handling in favor of exceptions. I’ve long preferred using `Result` (and its equivalents in other languages), and my experience so far with OCaml is that that preference is shared by many in the community and by authors of key libraries, but I was happy to consider a new counterpoint.

Doing so prompted me to consider my rationale(s) more than I had previously, and do some additional reading and research, all of which ended up further cementing my pro-`Result` bias. What follows are counterpoints to Bikal’s two most consequential arguments (in my opinion), and some elaboration beyond. Many thanks to Bikal for his posting his experience report!

### Stacktrace / Location Information

First, Bikal focuses in on how useful error handling should “allow us to efficiently, correctly and accurately identify the source of our errors”. I agree, but he compares exceptions and `result` on this basis like so:

> OCaml exception back traces - or call/stack traces - is one such tool which I have found very helpful. It gives the offending file and the line number in it. This make investigating and zeroing in on the error efficient and productive.
> 
> Using result type means you lose this valuable utility that is in-built to the ocaml language and the compiler.

It is true that `Error` does not _implicitly_ carry backtraces as exceptions do, but there is nothing preventing one from choosing to include a backtrace with a returned error, since OCaml backtraces helpfully exist separate from its exception facility:

```ocaml
let b x =
  if x > 0
  then Ok 0
  else Error ("unimplemented", Printexc.get_callstack 10)

let a x = b x

let _ = match a (int_of_string @@ Sys.argv.(1)) with
          | Ok v -> Format.printf "%d@." v
          | Error (msg, stack) ->
            Format.fprintf Format.err_formatter "Error: %s@." msg;
            Printexc.print_raw_backtrace stderr stack

```

```auto
$ ocamlc -g -o demo.exe src/demo.ml 
$ ./demo.exe -1
Error: unimplemented
Raised by primitive operation at file "src/demo.ml", line 5, characters 31-56
Called from file "src/demo.ml", line 9, characters 14-47

```

From a strictly ergonomic standpoint, it makes sense to wish that e.g. the `Error` constructor were treated specially such that values it produced always carried a stack trace (as exceptions do/are), so that programmers would not need to opt into it as above. However, that would not come without costs, including a maybe-significant runtime penalty that might render `Result` a less useful way to _cheaply_ signal recoverable error conditions (something that other exception-dominant languages/runtimes struggle to do given that stacktrace generation is far from free).

### Correctness

Bikal’s final topic was re: correctness, and to what extent using one or another error-handling mechanism tangibly affects his work. What he says is short enough to reproduce in full:

> I thought this would be the biggest advantage of using `result` type and a net benefit. However, my experience of **NOT** using it didn’t result in any noticeable reduction of _correct by construction_ OCaml software. Conversely, I didn’t notice any noticeable improvement on this metric when **using** it. What I have noticed over time is that abstraction/encapsulation mechanisms and type system in particular play by far the most significant role in creating **correct by construction** OCaml software.

There’s a lot left undefined here: what “correct by construction” might mean generally, what it means in the context of OCaml software development, how it could be measured (_is_ there a metric, or are we just reckoning here?), and so on.

While reminding myself of exactly what “correct by construction” meant, I came across a fantastic lecture by Martyn Thomas[1] that neatly defines it (and goes into some detail of how to go about achieving it); from the accompanying lecture notes[2]:

> …you start by writing a requirements specification in a way that makes it possible to analyse whether it contains logical omissions or contradictions. Then you develop the software in a way that provides very strong evidence that the program implements the specification (and does nothing else) and that it will not fail at runtime. We call this making software “correct by construction”, because the way in which the software is constructed guarantees that it has these properties.

While we aren’t working with anything as formal as a theorem prover when we are programming in OCaml, it does provide us with a tremendous degree of certainty about how our programs will behave. One of the greatest sources of that certainty is its default of requiring functions and pattern matches to be exhaustive with regard to the domain of values of the type(s) they accept; i.e. a function that accepts a `result` must provide cases for all of its known constructors:

```ocaml
let get = function Ok v -> v

```

```auto
$ ocamlc -g -o demo.exe src/demo.ml 
File "src/demo.ml", line 15, characters 10-28:
15 | let get = function Ok v -> v 
               ^^^^^^^^^^^^^^^^^^
Warning 8: this pattern-matching is not exhaustive.
Here is an example of a case that is not matched:
Error _

```

This one way we “provide evidence” to the OCaml compiler that our code does not not contain “logical omissions”, to use Prof. Thomas’ nomenclature.

There are ways to relax this requirement, though. Aside from simply telling the compiler to not bother us with its concerns via an attribute:

```ocaml
let get = function Ok v -> v [@@warning "-8"]

```

…we could simply use exceptions instead. For example, an exception-based variant of the program I started with earlier:

```ocaml
exception Unimplemented

let a x =
  if x > 0
  then 0
  else raise Unimplemented

let _ = Format.printf "%d@." @@ a (int_of_string @@ Sys.argv.(1))

```

This approach is less correct by any measure: the `Unimplemented` exception is not indicated in the signature of `a`, making it easy to call `a` without handling the exception, or being aware of its possibility at all. Insofar as the exceptions in question are not intended to be fatal, program-terminating errors, this approach absolutely increases the potential for “logical omissions”, increases the potential for programs to fail at runtime, and hobbles the exhaustivity guarantees that the OCaml compiler provides for us otherwise.

Later in the reparse announcement thread, @rixed said (presumably in response to this tension):

> If only we had a way to know statically which exceptions can escape any functions that would be the best of both worlds!

And indeed, this approach of incorporating known thrown exception types into function signatures is a known technique, (in)famously included in Java from the beginning (called _checked exceptions_), but widely disdained. I suspect that disdain was more due to Java’s other weaknesses in exception handling than the principal notion of propagating exception types in function/method signatures. It would be interesting to see something like checked exceptions experimented with in OCaml, though it may be that doing so would nullify one of the primary benefits that those preferring exceptions enjoy (perceived improved aesthetics/clarity), and/or the work needed to achieve this might approximate the typed effect handling approaches that @lpw25 et al. have been pursuing for some time.

[1]: _Making Software ‘Correct by Construction’_ [Making Software 'Correct by Construction'](https://www.gresham.ac.uk/lectures-and-events/making-software-correct-by-construction)  
[2]: [Making Software 'Correct by Construction'](https://www.gresham.ac.uk/lecture/transcript/download/making-software-correct-by-construction/)

---

<div class="post-metadata">

**Author:** ![bnguyenvanyen](https://avatars.discourse-cdn.com/v4/letter/b/7ea924/32.png) [@bnguyenvanyen](https://discuss.ocaml.org/u/bnguyenvanyen)\
**Post date:** [December 7, 2020, 7:54pm UTC](https://discuss.ocaml.org/t/exception-vs-result/6931/2 "2020-12-07T19:54:21Z")

</div>

Just chiming in to note that there has been an interesting discussion on this topic two years ago: [Specific reason for not embracing the use of exceptions for error propagation?](https://discuss.ocaml.org/t/specific-reason-for-not-embracing-the-use-of-exceptions-for-error-propagation/1666/40)

It’s also interesting to note that that discussion also ended up talking about typed effects.  
As I understand it, they would indeed subsume checked exceptions, and I’m quite excited about them.

---

<div class="post-metadata">

**Author:** ![cemerick](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/cemerick/32/1383_2.png) [@cemerick](https://discuss.ocaml.org/u/cemerick)\
**Post date:** [December 7, 2020, 8:04pm UTC](https://discuss.ocaml.org/t/exception-vs-result/6931/3 "2020-12-07T20:04:52Z")

</div>

Yes, thank for linking to that. There are actually a half-dozen relevant threads on this forum (and some in stackoverflow) on this topic, but I didn’t want to either blindly dump them all in the post, or try to write around them. 🙂

The main insight for me that I hadn’t considered explicitly before was that the transformation of a function from returning a `result` to potentially throwing an exception is equivalent to eliding a compiler error on a nonexhaustive pattern match. The consequences for correctness are…notable?

---

<div class="post-metadata">

**Author:** ![c-cube](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/c-cube/32/1727_2.png) [@c-cube](https://discuss.ocaml.org/u/c-cube)\
**Post date:** [December 7, 2020, 8:24pm UTC](https://discuss.ocaml.org/t/exception-vs-result/6931/4 "2020-12-07T20:24:32Z")

</div>

I think it depends on the use case. In rust and other languages, you have a distinction between recoverable (`result`) and unrecoverable (`panic`) errors. In some fields most errors will be unrecoverable: if you write a compiler or a theorem prover, exceptions are nice because there’s not much you can do if things fail imho. In other cases, you may have a lot of IO errors where you can retry on error.

At API boundary I think `result` is generally better in 2020, it documents better. Within a program I’m not always convinced it’s better.

---

<div class="post-metadata">

**Author:** ![Chet\_Murthy](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/chet_murthy/32/1501_2.png) [@Chet\_Murthy](https://discuss.ocaml.org/u/Chet_Murthy)\
**Post date:** [December 7, 2020, 9:33pm UTC](https://discuss.ocaml.org/t/exception-vs-result/6931/5 "2020-12-07T21:33:55Z")

</div>

I’m going to address the general issue of “programming with monads”, and not specifically the result monad, b/c I think it’s just an instance of the general phenomenon.

TL;DR In 1992, when someone told me about “programming with monads”, I replied that I _already_ programmed with monads: I used the “SML Monad”. And this LtU post seems to me to be pithily succinct ( [Are Monads a Waste of Time? | Lambda the Ultimate](http://lambda-the-ultimate.org/node/5504) )

(1) when we talk about program correctness, we mean two things: reasoning about programs, and type-safety. I’ll address each in turn below.

(2) All monadic transformations of which I am aware (exceptions, state, control, I/O) are direct equivalents to the “standard semantics” for such language-features, e.g. as described in Michael J.C. Gordon’s book _The Denotational Description of Programming Languages_. **Programming with monads is programming with some combinators and macros, on the right-hand-side of the denotational interpreters** in that book.

(3) “reasoning about programs” has historically meant “equational reasoning”, and IIUC, Felleisen&Sabry’s work (and follow-on works) proved pretty conclusively that anything you can prove about the right-hand-side of the denotational semantics interpeter defiition, you can “pull back” to equational reasoning with extra rules, on the left-hand-side of the DS interpreter.

(4) “type safety”:

> If only we had a way to know statically which exceptions can escape any functions

There was a cottage industry of “effect type systems” to capture/reason-about exceptions, state, maybe other things, decades ago. They were judged too cumbersome for programmers to use, and hence died-out. \>10yr ago there was a caml-light (OCaml?) variant that checked exceptions in function-types; it didn’t catch on. Look at Java, where some exceptions are “checked” and others are not: some exceptions, it’s just too cumbersome to track in the type system. And so either your “result” monad only captures some of the exceptions, or it’s going to be wildly cumbersome.

(5) Monads are less-efficient than direct-style, memory-wise. For me, the moment in 1992 when I (an avowed SML/NJ bigot) became convinced of the superiority of caml-light (notwithstanding 2.5x slower on average) was when I realized that it was -so- much less memory-intensive. Because it didn’t allocate stack-frames on the heap, and closures started out on the stack and only moved to the heap on-demand. Henry Baker made the observation \>20yr ago that the stack is a form of nursery. Writing in monadic style is sacrificing this obviously performance advantage. In the era of multicore, arguments made back then about memory, can be recast as arguments about the cache today, since (as hardware designers put it) “memory is at infinity” today.

P.S. And yet, I use monads sometimes, too. Rarely. But for instance, it’s a good model for (e.g.) writing a type-checker that wants to type-check a list of expressions (no unification, hence no side-effects) and not stop at the firs type-error, but rather gather together errors from all the expressions in the list, and produce an error with all of them combined. So the type-checker at the top of each member of the list catches any raised exception, stores it in an accumulator, and goes on to the rest of the list; at the end of the list, if the accumulator is empty, it returns the list of result-types; otherwise it raises an exception containing list of errors stored in the accumulator.

It’s rare, and if the Result monad didn’t exist, I’d hack something together, but … it’s literally the only use I can think of, that wasn’t driven by a library (e.g. `bos`) using the Result monad itself (and my needing to use that library).

And this _efficiency_ is the real reason that exception-based backtraces are better: IIUC, OCaml exceptions are _really_ cheap because they don’t materialize that backtrace until demanded. It means that you have to be careful what code you put between the “try-with” and the demand for the backtrace, but it’s _efficient_. Materializing the backtrace for every exception raised would be … pretty horrendously inefficient, and yet that’s what you have to do if you use the result monad.

---

<div class="post-metadata">

**Author:** ![c-cube](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/c-cube/32/1727_2.png) [@c-cube](https://discuss.ocaml.org/u/c-cube)\
**Post date:** [December 7, 2020, 9:39pm UTC](https://discuss.ocaml.org/t/exception-vs-result/6931/6 "2020-12-07T21:39:39Z")

</div>

If we had typed effects (or at least checked exceptions, a restricted form of typed effects) I think it’d be strictly superior to the result monad, too. The problem with monads, in addition to the performance/allocation overhead, is that they compose super badly with all the existing control flow constructs except for function calls. Java’s checked exceptions are not representative of the concept as they never tackled properly the interaction with generics. Done properly, in OCaml, we’d need effects on arrows so that, say, `List.map` propagates the exception of its functional argument.

---

<div class="post-metadata">

**Author:** ![cemerick](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/cemerick/32/1383_2.png) [@cemerick](https://discuss.ocaml.org/u/cemerick)\
**Post date:** [December 7, 2020, 9:57pm UTC](https://discuss.ocaml.org/t/exception-vs-result/6931/7 "2020-12-07T21:57:20Z")

</div>

> [@c-cube](#):
>
> At API boundary I think `result` is generally better in 2020, it documents better. Within a program I’m not always convinced it’s better.

Yeah, I am very wary of libraries that use exceptions liberally. As it stands, my most frustrating OCaml production bugs have been cases where a library raised an exception that I wasn’t expecting, wasn’t documented, and IMO had no reason to expect, given the calling context.

I do use exceptions on occasion, but almost always for bounded non-local returns (equivalent to labelled break or goto).

---

<div class="post-metadata">

**Author:** ![Chet\_Murthy](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/chet_murthy/32/1501_2.png) [@Chet\_Murthy](https://discuss.ocaml.org/u/Chet_Murthy)\
**Post date:** [December 7, 2020, 10:00pm UTC](https://discuss.ocaml.org/t/exception-vs-result/6931/8 "2020-12-07T22:00:19Z")

</div>

I don’t know much about how people compose monads (I use the already-composed exception+state+threads+IO monad called “the OCaml compiler”)[1] but I hear there’s this “tagless final something-or-other” that might be relevant. No idea how it works.

But even if monads composed well, and worked for the entire core language, they still don’t work at functor-application and structure-items, right?

[1] One of the arguments made _for_ monads, is that (with the control/threading monad) it allows you to know when-and-where you’ll be time-sliced away, and hence where you have to reason about side-effects. And sure, that’s all fine and dandy in theory. I once worked with a “green threads” system for Python where all context-switches happened with a fixed set of primitive operations: with even a modestly-complex library of code built on-top, you were no longer able to divine where you would or would not be context-switched, and hence had to assume that you could be context-switched anywhere. It was (as I remember putting it) “it feels like a context switch can happen at any newline”. Which is … well, exactly how it feels to use a regular threading system, pretty much. [ok, substitute “any whitespace character”]

---

<div class="post-metadata">

**Author:** ![Leonidas](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/leonidas/32/4039_2.png) [@Leonidas](https://discuss.ocaml.org/u/Leonidas)\
**Post date:** [December 8, 2020, 2:34am UTC](https://discuss.ocaml.org/t/exception-vs-result/6931/9 "2020-12-08T02:34:28Z")

</div>

> [@cemerick](#):
>
> As it stands, my most frustrating OCaml production bugs have been cases where a library raised an exception that I wasn’t expecting, wasn’t documented, and IMO had no reason to expect, given the calling context.

Oh, that sounds like a case of `Not_found`, an exception that is frustrating because it is so easy to overlook cases where it is thrown as well as quite contextless, since it actually does not specify what wasn’t found. These undocumented exception cases are easy to get wrong because sometimes the author of that code you’re using also wasn’t expecting it, so the surprise is both to you and the library author.

I tend to use exceptions in OCaml in a way inspired by Rust: as panics, to terminate the program when the failure is not recoverable. When I e.g. know that the user hasn’t submitted the required input. Or, as @cemerick mentions, as non-local returns, but then I would guard them.

A similar annoyance to me are by the way `Lwt.t` promises which, along with being resolved or unresolved can also “fail”, thus forming an unholy alliance of promises and exceptions. It seems like the maintainers of Lwt are aware of this initial design flaw and ship with `Lwt_result` which handles `result` nested in `Lwt.t` (so, exactly as `Deferred.Result.t` in Async).

---

<div class="post-metadata">

**Author:** ![yawaramin](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/yawaramin/32/3384_2.png) [@yawaramin](https://discuss.ocaml.org/u/yawaramin)\
**Post date:** [December 8, 2020, 3:22am UTC](https://discuss.ocaml.org/t/exception-vs-result/6931/10 "2020-12-08T03:22:47Z")

</div>

Cristiano Calcagno has been doing some pretty interesting work on this: [reanalyze/EXCEPTION.md at 72712393459d7e132c78e0700abffc5fc4cd09b8 · rescript-association/reanalyze · GitHub](https://github.com/reason-association/reanalyze/blob/72712393459d7e132c78e0700abffc5fc4cd09b8/EXCEPTION.md)

Let me quote the central concept from there:

> The exception analysis is designed to keep track statically of the exceptions that might be raised at runtime. It works by issuing warnings and recognizing annotations. Warnings are issued whenever an exception is raised and not immediately caught. Annotations are used to push warnings from he local point where the exception is raised, to the outside context: callers of the current function. Nested functions need to be annotated separately.

---

<div class="post-metadata">

**Author:** ![cemerick](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/cemerick/32/1383_2.png) [@cemerick](https://discuss.ocaml.org/u/cemerick)\
**Post date:** [December 8, 2020, 4:57am UTC](https://discuss.ocaml.org/t/exception-vs-result/6931/11 "2020-12-08T04:57:12Z")

</div>

> [@Leonidas](#):
>
> Oh, that sounds like a case of `Not_found` , an exception that is frustrating because it is so easy to overlook cases where it is thrown as well as quite contextless, since it actually does not specify what wasn’t found. These undocumented exception cases are easy to get wrong because sometimes the author of that code you’re using also wasn’t expecting it, so the surprise is both to you and the library author.

\*\*_ding ding ding ding_\*\*

One time was my fault directly (via some of my earliest OCaml code where I used `find` without thinking much about it), the other was exactly the scenario you describe where a borderline edge case parameter to a library function (I think it was an empty string) ended up touching a map with a non-existent key, alas.

I’m certain I’ve groused in irc about `Map.S.find` being exception-oriented, while the IMO saner semantics are found under the less-natural/longer `find_opt`. Defaults matter for things like this, so I greatly prefer the `foo_exn` naming convention for function variants that raise instead of return.

---

<div class="post-metadata">

**Author:** ![fdagnat](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/fdagnat/32/88_2.png) [@fdagnat](https://discuss.ocaml.org/u/fdagnat)\
**Post date:** [December 8, 2020, 8:32am UTC](https://discuss.ocaml.org/t/exception-vs-result/6931/12 "2020-12-08T08:32:26Z")

</div>

François Pessaux worked on exception inference 20 years ago see for example [https://hal.inria.fr/inria-00073144](https://hal.inria.fr/inria-00073144). I remember there was an implementation for Ocaml but I have not been able to find quickly its name or a link…

---

<div class="post-metadata">

**Author:** ![orbitz](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/orbitz/32/110_2.png) [@orbitz](https://discuss.ocaml.org/u/orbitz)\
**Post date:** [December 8, 2020, 8:49am UTC](https://discuss.ocaml.org/t/exception-vs-result/6931/13 "2020-12-08T08:49:24Z")

</div>

This sounds like the main checked-exceptions in Java gave the world. By adding a single exception deep in the stack you had to either handle it immediately or modify the entire call chain. There is a lot of Java code to convert a checked exception into a runtime exception just because it’s too annoying to do right, which means a lot of code handlers errors badly.

---

<div class="post-metadata">

**Author:** ![orbitz](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/orbitz/32/110_2.png) [@orbitz](https://discuss.ocaml.org/u/orbitz)\
**Post date:** [December 8, 2020, 9:00am UTC](https://discuss.ocaml.org/t/exception-vs-result/6931/14 "2020-12-08T09:00:52Z")

</div>

I wrote two blog posts on my experience using `result` awhile ago, linked below. Much of it still holds. Many of the pain points others have mentioned do exist, but in my judgement, _given the current state of Ocaml_, results are strictly better (at the very least at the API boundary, assuming you can convince yourself no exceptions escape it) than exceptions. I also believe that the reasonable error values are necessary. For example, I know some APIs like some variation of `('a, string) result` which, IMO, is not a great API as I end up comparing strings and hoping the string value is actually part of the API and not some rando value tossed in there. Double for when meaningful aspects of the error are encoded in the string and I have to decode it to decide what to do.

For my own things I do require that all errors are convertible to a string so I can just show them to the user, this is especially important for development and debugging, IME. This is one of the few places where I do wish we had something like type classes so I could do something like:

```ocaml
foo ()
>>= function
| Ok () -> yadda
| Error err -> show err

```

YMMV

> **[Experiences using Result.t vs Exceptions in Ocaml](http://functional-orbitz.blogspot.com/2013/01/experiences-using-resultt-vs-exceptions.html)**
>
> Disclaimer: I have not compiled any of the example code in this post. Mostly because they are snippets meant to illustrate a point rather ...

> **[Introduction to Result.t vs Exceptions in Ocaml](http://functional-orbitz.blogspot.com/2013/01/introduction-to-resultt-vs-exceptions.html)**
>
> This post uses Jane St's Core suite. Specifically the Result module. It assumes some basic knowledge of Ocaml. Please check out Ocaml.o...

---

<div class="post-metadata">

**Author:** ![Chet\_Murthy](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/chet_murthy/32/1501_2.png) [@Chet\_Murthy](https://discuss.ocaml.org/u/Chet_Murthy)\
**Post date:** [December 8, 2020, 9:06am UTC](https://discuss.ocaml.org/t/exception-vs-result/6931/15 "2020-12-08T09:06:03Z")

</div>

Regarding pretty-printing the exception, why isn’t deriving.show sufficient? IIRC, it supports pretty-printing of extensible variants, and exceptions are such … I remember when I implemented my camlp5/pa\_ppx version of deriving.show, I supported extensible variants, and use it to pretty-print exceptions, mimicking the code in either deriving.show, or in deriving.yojson (I forget which, and it’s too late at night or me to go look it up).

---

<div class="post-metadata">

**Author:** ![Taki](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/taki/32/718_2.png) [@Taki](https://discuss.ocaml.org/u/Taki)\
**Post date:** [December 8, 2020, 9:14am UTC](https://discuss.ocaml.org/t/exception-vs-result/6931/16 "2020-12-08T09:14:58Z")

</div>

It seems that we had some discussion on this

> [@Why not place exn in function signature?](https://discuss.ocaml.org/t/why-not-place-exn-in-function-signature/1855/7):
>
> I believe there are difficuties with checked exceptions and higher-order functions. For example, how would you write the type for List.map if the function taken in the first parameter can throw an arbitrary exception? You’d end up having to use some generic exception annotation and lose the specific error information anyway.

---

<div class="post-metadata">

**Author:** ![mro](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/mro/32/2496_2.png) [@mro](https://discuss.ocaml.org/u/mro)\
**Post date:** [December 8, 2020, 11:19am UTC](https://discuss.ocaml.org/t/exception-vs-result/6931/17 "2020-12-08T11:19:18Z")

</div>

the part in the video at t=20m47s where Prof Thomas tells about the training course after years how to start the system because the operators forgot – that’s hilarious.

---

<div class="post-metadata">

**Author:** ![keleshev](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/keleshev/32/3779_2.png) [@keleshev](https://discuss.ocaml.org/u/keleshev)\
**Post date:** [December 8, 2020, 1:17pm UTC](https://discuss.ocaml.org/t/exception-vs-result/6931/18 "2020-12-08T13:17:50Z")

</div>

A bit late to the party, but here’s an overview of error handling methods that I did a while ago:

[Composable Error Handling in OCaml (keleshev.com)](https://keleshev.com/composable-error-handling-in-ocaml)

It compares the following approaches:

- Exceptions
- Result type with strings for errors
- Result type with custom variants for errors
- Result type with polymorphic variants for errors

---

<div class="post-metadata">

**Author:** ![keleshev](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/keleshev/32/3779_2.png) [@keleshev](https://discuss.ocaml.org/u/keleshev)\
**Post date:** [December 8, 2020, 8:07pm UTC](https://discuss.ocaml.org/t/exception-vs-result/6931/19 "2020-12-08T20:07:37Z")

</div>

I have re-read the article and decided to update it to use the recently-introduced `Stdlib.Result` module and `(let*)` syntax: [https://keleshev.com/composable-error-handling-in-ocaml](https://keleshev.com/composable-error-handling-in-ocaml)

---

<div class="post-metadata">

**Author:** ![gadmm](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/gadmm/32/877_2.png) [@gadmm](https://discuss.ocaml.org/u/gadmm)\
**Post date:** [December 8, 2020, 11:35pm UTC](https://discuss.ocaml.org/t/exception-vs-result/6931/20 "2020-12-08T23:35:44Z")

</div>

> [@Chet\_Murthy](#):
>
> And this _efficiency_ is the real reason that exception-based backtraces are better: IIUC, OCaml exceptions are _really_ cheap because they don’t materialize that backtrace until demanded. It means that you have to be careful what code you put between the “try-with” and the demand for the backtrace, but it’s _efficient_ . Materializing the backtrace for every exception raised would be … pretty horrendously inefficient, and yet that’s what you have to do if you use the result monad.

This tends to be defeated by the implementation of `Fun.protect` that always saves the backtrace just in case. If you use exceptions for performance you will more and more have to use `raise_notrace` where it matters.

[Next page](https://discuss.ocaml.org/t/exception-vs-result/6931.md?page=2)
