dotnet / fsharp

The F# compiler, F# core library, F# language service, and F# tooling integration for Visual Studio
https://dotnet.microsoft.com/languages/fsharp
MIT License
3.91k stars 785 forks source link

Result module missing some useful functions #7716

Closed pema99 closed 5 years ago

pema99 commented 5 years ago

Is your feature request related to a problem? Please describe. Since F# 4.1 we have the Result<'T, 'TError> type which is nice for railway oriented programming. Compared to the similar Option<'T> type I feel both the Result type and corresponding module are somewhat lacking in implementation. The Option type allows to use members such as Value, IsNone and IsSome, where as Result has nothing like this. Additionally, the Result type has no overloaded ToString() method, is there any reason for this? Furthermore the Result module is missing some useful functions. Again, like Option has Option.isSome and Option.isNone we do not have anything corresponding to this for Result. Functions for getting the values is contained in the Result are also non-existant, whereas Option.get exists for Options. Lastly, I think having functions to get values contained in Result (either in Error or Ok union cases), but returning Options instead of throwing exceptions would be useful.

Describe the solution you'd like At the very least, implement the following methods for Result<'T, 'TError> (names obviously are not final):

- IsOk (like Option's IsSome)
- IsError (like Option's IsNone)
- ValueOk, ValueError (like Option's Value, for both Ok and Error)
- Overrided ToString()

And implement the following functions in the Result module:

Result.isOk:     Result<'T, 'TError> -> bool
Result.isError:  Result<'T, 'TError> -> bool
Result.getOk:    Result<'T, 'TError> -> 'T
Result.getError: Result<'T, 'TError> -> 'TError

And perhaps these functions as well:

Result.tryGetOk:    Result<'T, 'TError> -> 'T option
Result.tryGetError: Result<'T, 'TError> -> 'TError option

Describe alternatives you've considered Implementing these on an ad-hoc project-to-project basis, which is what I have been doing.

maxdeviant commented 5 years ago

Result already has ResultValue and ErrorValue visible from C# projects. However, I don't think these should be exposed in F#, as they allow for the misuse of Result.

In fact, I think that the presence of Value, IsSome, and IsNone on Option is actually a bug. I've seen plenty of new F# users fall into the trap of using them instead of using pattern matching to unwrap the values properly.

I would be in favor of adding functions to the Result module that retrieve the Ok or Error values wrapped in an Option. There is prior art for this in Rust, which has .ok() and .err().

abelbraaksma commented 5 years ago

Since the whole idea with Result is to work with scenarios that can contain errors, I think introducing functions that cannot do anything else but throw when the expected union is not set, it's a bad design smell. This is true for getError and getOk.

The isOk and isError will be implemented as instance methods once the hidden members are made available (issue is currently in RFC).

The tryXx members are perhaps better suited as a toOption function, which is indeed missing, but trivial to implement.

I do believe that more functions are warranted in line with options, especially considering we only have bind, map, mapError, but probably not these functions. Also, I thought there was already a discussion on what set should be added, but the link escapes me.

pema99 commented 5 years ago

@abelbraaksma Is this what you are thinking of? I'd like to read this discussion.

cartermp commented 5 years ago

Closing in favor of the FSLang suggestion: https://github.com/fsharp/fslang-suggestions/issues/623