John Doe
John Doe

Reputation: 493

Return an exception with the Result type

I'm trying use the errors that F# has by default: the exceptions.

I want handle the errors with the Result type, but if I try return a specialization of Exception, like ArgumentException, as error, Visual Studio says "this function takes too many arguments, or is used in a context where a function is not expected".

My source:

let division (x: float) (y: float): Result<float, Exception> =
    if x = 0.0 then
        Error (ArgumentException ())
    else
        Ok (x / y)

Upvotes: 3

Views: 1725

Answers (2)

Anton Schwaighofer
Anton Schwaighofer

Reputation: 3149

You mixed up types and values (update: this answer refers mostly to the first version of your post, TomasP's answer is better for the updated code)

  • In the method signature, Exception is the type argument to the generic Result type.
  • In the method body, when you construct your return value, you need to call Error with an instance of the Exception type.

You need to actually invoke the operation that could throw (x/y usually does not, as pointed out in the comments), catch the exception, and then return that:

let division (x: float) (y: float): Result<float, Exception> =
    try
        let result = SomethingThatCouldThrow x y
        Ok result
    with 
    | e -> Error e

Btw, I do not understand your goal of "use the errors that F# has by default: the exceptions." The .Net default handling of an error condition is exceptions, yes. But what you are returning here a class that wraps the exception (in the error case).

Upvotes: 3

Tomas Petricek
Tomas Petricek

Reputation: 243126

The problem with your code is that the type of newly created ArgumentException is not the same as the Exception type which you specified in the type signature.

You can cast ArgumentException to Exception safely using the :> operator, but F# does not insert the cast automatically, so you have to write it yourself:

let division (x: float) (y: float): Result<float, Exception> =
    if x = 0.0 then
        Error (ArgumentException () :> Exception)
    else
        Ok (x / y)

In fact, F# can even infer the target type from the type annotation, so you can write just:

Error (ArgumentException () :> _)

PS: I see that you are saying you're getting "the function takes too many arguments" error. This is quite strange and perhaps there is something more going on in your case. The error that I get when I try your code is "This expression was expected to have type Exception but was ArgumentException" so perhaps you are also redefining some of the standard types...

Upvotes: 5

Related Questions