softshipper
softshipper

Reputation: 34071

Handling exception in the right way

I am pretty new in f# world. I wrote a very small application that query data from sap and show the result as output. When the application try to connect sap, it could throw some exceptions, in case something goes wrong.

Look at following code:

type Customer() =
    let mutable _lastName = String.Empty
    member self.LastName with get () = _lastName

    member self.QueryData () =
        //Some CODES here

        let bapi = SapBapi()
        let bapiFunc = bapi.GetBapiFunc(dest, "BAPI_CUSTOMER_GETDETAIL1")
        match bapiFunc with
        | Success bp  ->
            //Some CODES here

            let addressData = bp.GetStructure("PE_PERSONALDATA")
            _lastName <- addressData.GetString("LASTNAME")
            None 
        | RfcCommunication ex ->
            Some(ex :> Exception)
        | RfcLogon ex ->
            Some(ex :> Exception)
        | RfcAbapRuntime ex ->
            Some(ex :> Exception)

As you can see, I handle the error with option type and downcast the throwed exception to base exception type.

In the main function

open CustomerBapi
open System

[<EntryPoint>]
let main argv = 

    let customer = CustomerBapi.Customer()
    let ex = customer.QueryData()

    match ex with 
    | Some ex ->
        printfn "%s" ex.Message
    | None ->
        printfn "%s" customer.LastName

    Console.ReadLine() |> ignore
    0 // return an integer exit code

This code works but do I handle exception in the right way?

I read an article in internet, that handling exception in f# should return an error code, it's more easy then the exception style.

Upvotes: 1

Views: 123

Answers (2)

scrwtp
scrwtp

Reputation: 13577

A typical way of handling errors within the type system is to employ an Either type.

 type Either<'a,'b> =
     | Left of 'a
     | Right of 'b

Conventionally Right value carries the success result and Left carries an error or exception (either as a string or an exc type). A simple way to think about it is to treat it like an option where Right corresponds to the Some case and instead of a None you have error information.

So your code could become:

// QueryData no longer needs to depend on side effects to work, 
//so you can make it a regular function instead of a method
let result = queryData()

match result with 
| Left ex ->
    // handle exception
    printfn "%s" ex.Message
| Right result ->
    // either set the property, or make customer a record
    // and set the name field here
    customer.LastName <- result
    printfn "%s" customer.LastName

The bit about error codes sounds very wrong, would like to know where you found it.

Upvotes: 2

weismat
weismat

Reputation: 7411

In general I think that your solution is okay, but can be improved.
You mix a bit the functional and OO style in your code. It feels a bit strange to me that you are working with the exception as the only optional value. Usually the customer should be the value which has the optionality included and the match should be if the customer has a value or not.

Upvotes: 0

Related Questions