I completely disagree with this article, as it makes a lot of claims which are not true, uneducated or intentionally misrepresented to make a case for exceptions:
> Because runtime errors are difficult to anticipate, I claim that using result types as a holistic replacement for error handling in an application is a leaky abstraction.
Yes this is true, but it's not a leaky abstraction. There's always the posibillity that shit hit the fan and something happened which was unexpected and indicates an unhealthy system in which case it will result in an unanticipated exception such as a RuntimeException.
This is ok, that's why every application has somewhere a global error handler, which can capture that unusual exception, log it and potentially terminate the application or put it in an unhealty state so that a higher level scheduler can replace or re-start the app. Possibly even raise some emergency alerts with developers via PagerDuty, etc.
However, it most certainly doesn't leak anything or makes the Result type less useful, because most application errors are anticipated due to a combination of user inputs or other external factors such as API calls and these can be perfectly handled in a more predictable way by using a Result type.
> It’s by such misadventure that the working F# programmer soon realizes that any function could still potentially throw. This is an awkward realization, which has to be addressed by catching as soon as possible.
Not really. There's nothing awkward about a runtime exception. Shit sometimes happen. And it's not true that it has to be handled as early as possible. As said before, you only have to deal with exceptions in a global error handler. If the error must be caught as early as possible, then it means that there is a possible plan B and a possible plan B can only exist if the error is anticipated. If it is anticipated then it should be returned in a Result type. So fundamentally exceptions are not awkward. When they happen there's exactly only one place where they need to get handled and the rest of the application code just works with Result types where errors are possibly known.
> In the majority of codebases using result types that I’ve been reviewing, people typically just end up re-implementing exception semantics on an ad-hoc basis. This can result in extremely noisy code...
So he has just worked with badly written code. If all the code is doing is bubbling up an error from the Result type then whats the point of returning that error? Return errors which are meaningful and where the calling code can deal with it immediately, otherwise don't bother.
> An important property of exceptions -which cannot be stressed enough- is that they are entities managed and understood by the underlying runtime, endowed with metadata critical to diagnosing bugs in complex systems. They can also be tracked and highlighted by tooling such as debuggers and profilers, providing invaluable insight when probing a large system. By lifting all of our error handling to passing result values, we are essentially discarding all that functionality.
Well as said before, the Result type is not to be logged or thrown or something. It's there so calling code can deal with it - implement some sort of plan B. If all the author wants is to always log the entire exception including stack trace for every error and not really deal with it then fair enough, just use exceptions everywhere, but that application will suck big time.
> That said, I strongly believe that using result types as a general-purpose error handling mechanism for F# applications should be considered harmful.
Functions are Input -> Output. If you don't like that as a "general" mechanism, and you prefer Input -> Output, Exception, {whatever} then use OOP and not FP. It almost seems like that the author just doesn't like the functional appraoch in functional programming, which is a weird point to make.
> Exceptions should remain the dominant mechanism for error propagation when programming in the large.
Based on which logic? That's such a generalisation that it's just plain wrong. Exceptions are try-catch error handling and there is no proof that try-catch is the ultimate error handling solution. Lots of new languages make an effort to exactly not do that, so where's the evidence?