Hi Ben,

2014-05-26 17:13 GMT+02:00 Ben Millwood <bmillwood@janestreet.com>:
First of all, it seems to be universal among all languages I've much experience with that there are unchecked exceptions. Your program might be interrupted at any point by an out of memory error or a signal or something, and there's just not much you can do about that. You can either model it in your code or not, but you can't stop it from happening. So it seems like the best we can hope for with typed exceptions is in addition to unchecked ones, to make it possible (but not required) that a function might declare some of the exceptions it can throw.

That's perfectly right.
 

But after all exceptions are just "things I can return instead of a result", and lightweight sum types are already pretty good at that. E.g. (to use Romain's syntax)

    val lookup : map -> key -> value raise Not_found

is pretty much just the same as:

    val lookup : map -> key -> value option

Right. This is a very good use case that I adopted thanks to core.
 

True, exceptions get automatic propagation, but the option monad interface makes that pretty lightweight, and you can do a similar thing with a less trivial sum type if you need richer type information.

Using options or Result from time to time is certainly a nice habit. However to be honest, using option/result monads extensively does not seem right to me, like pulling the language in a direction it was not really designed for. Monad combinators do a great job at propagating errors, but still there is a serious addition of plumbing in function body's and Result returning functions have a significantly less readable type. But I guess this is pretty much a question of taste/habit to see if the added verbosity is worth it.
 

See also: https://blogs.janestreet.com/how-to-fail-introducing-or-error-dot-t/ for discussions of more ways you can make error handling both explicit and concise.

Thanks! BTW core still uses exceptions. Is there an explicit rule as to how to decide between Result type or exceptions. For instance, why not write the Array.create function like this:

val create : int -> 'a -> 'a array Or_error.t

where create fails for a negative integer?