3 ms·
As a daily user of F# I'm not sold on this suggested alternative. It seems to be trying to make it as easy as possible to make the Result type behave like excep
by omcnoe 2y ago
As a daily user of F# I'm not sold on this suggested alternative.
It seems to be trying to make it as easy as possible to make the Result type behave like exception handling, but I think there are some key downsides to the approach.
First, Result is often used in place of Choice only to communicate the intent that the 2nd case is an error case. Making it more work to use Result (by requiring the types used for the Error to implement some special interface) means programmers will simply use Choice instead.
But the bigger issue is that this suggested change would remove the ability to ensure that cases of an error type are exhaustively matched. They introduce the FailAs active pattern at the very end of the blog to deal with logic that wants to inspect the underlying error cases, but active patterns break the compilers ability to check if a match is exhaustive. This is a really useful property for program correctness, I can ensure that a caller of my function will receive a compiler error when a new error case is introduced that wasn't previously handled.
I wonder if a better design for the error type could be some kind of error type set that could automatically collect possible error cases up the call stack, so that when confronted with an IFault you at least know what possible cases it could have. With some type inference help it might not even be that painful to deal with, the first example could automatically infer a type like Errors<AtlasError, ForExError>.
As touched on briefly in the article, the elephant in the room here is that changing the Result type doesn't do anything to unify the two distinct worlds of exceptions vs error values that currently exist in F#. Dealing with obscure C# exception flow from F# has been the biggest source of subtle, hard to track down bugs in my production code.
- needlesslygrim 2y agoI agree, this doesn't seem to be much better than adding `throws Throwable` to all your methods that can fail in Java. The reason sum types are so useful for error handling is that all possible cases can be exhaustively checked against at compile time.
- nozzlegear 2y agoI'm also a daily user of F#, and like you I'm not totally sold on this alternative. However, at first glance (without using it in a real life scenario) I like it more than the Result type we have. One of the apps I have in production right now leans heavily on using Results, and the biggest pain point — besides handling exceptions from C# world — is the mapping of the different Result error types. It can get tedious, especially when you're three Results deep in a "railway" and each operation needs its own custom mapping because they use different Result types. Before reading this article, I'd decided that if I had to do it again I'd just throw exceptions, but now I'm wondering whether or not I'd play around with enforcing an IFault interface.