On 26 May 2014 17:02, Philippe Veber wrote: > > 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. > It's true that using a monadic style does introduce *some* noise, but I don't think it's so bad, especially if you design your API to fit with the style. In a way I almost prefer having the binds there so that I can easily see where the possible interruption points in the flow are, and in particular it's /syntactically/ obvious where errors /can't/ occur. 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? > Daniel's summary is very good, although we do use Failure in Core, often for assertion-failure like scenarios or just any case where the error isn't meant to be handled specifically. In many cases Invalid_argument would arguably be more appropriate, but in other cases that isn't obvious (say if you mutate a Queue.t while you are folding over it, that will be detected and an error will be thrown, but it isn't /really/ an invalid argument error), and in any case since we often don't intend to catch them except to print a stack trace and die, it doesn't matter too much. We also do just break our own rules sometimes. Possible reasons why are: - some aspect of usability takes priority over dogmatics (although this is much rarer than you'd think) - legacy exceptions (see below) - sometimes we make bad decisions :( Having no experience on large projects, it is not clear to me why > exceptions are considered so dangerous. One point I see is that when you > decide to handle errors with a try ... with expression, there is no > exhaustivity check to ensure you handled all possible cases, and that you > have to rely on (possibly incomplete) documentation and reasonning to > convince yourself you forgot nothing. Another related one is that there is > no automatic analysis to show exceptions thrown by a function in the > documentation. These are of course already strong reasons why not to use > too many exceptions (and were the motivation for my initial question). Do > you see other reasons? > One particularly galling aspect of exceptions not showing up in types is that they can't easily be refactored. If you decide to change which exceptions a given function throws, you can't rely on the typechecker to flag up where code was written to the old specification and needs changing. You can't even just eyeball the code to see where the function was used and see if the exception was caught, because who knows where in the call stack it might have been handled? Explicit error types, on the other hand, will refuse to compile unless you have changed your code to deal with it, so you can make your errors richer or more precise with a high level of confidence that you haven't introduced any "holes" for exceptional conditions to sneak out where previously they couldn't. This is essentially why we still have a few Not_found exceptions in Core, because it's really pretty hard to know where they might be relied upon, so it's easier to leave them in than purge them and risk silent breakage.