Handling exception in the right way - f#

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.

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.

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.

Related

How to handle exceptions in F# when using sequence expressions?

I am trying to write a F# function that reads a CSV file and returns its lines as a sequence of strings that can be further processed in a pipelined expression. The function should handle all exceptions that can arise when opening and reading a file. This is what I came up with so far:
// takes a filename and returns a sequence of strings
// returns empty sequence in case file could not be opened
let readFile (f : string) =
try
seq {
use r = new StreamReader(f) // if this throws, exception is not caught below
while not r.EndOfStream do
yield reader.ReadLine() // same here
}
with ex
| ex when (ex :? Exception) ->
printfn "Exception: %s" ex.Message
Seq.empty
The problem here is that the exceptions that could be thrown by StreamReader() and ReadLine() are not caught in the exception handler but instead are left uncaught and lead to program termination. Also, there seems to be no way of trying to catch exceptions inside the seq {} sequence expression. Right now I cannot think of any other way to design such a function than reading the whole file into an intermediate collection like a list or an array beforehand and then returning this collection as a sequence to the callers, thereby loosing all the benefits of lazy evaluation.
Has anybody got a better idea ?
The reason the exceptions are not caught by the try-with handler here is that the body of the seq is lazily executed. readFile returns the sequence without generating an exception, but then trying to execute that sequence generates an exception in the context where it is being used.
Since F# doesn't let you use try-with within a sequence expression, you have to be a bit creative here. You could use Seq.unfold to generate the sequence like so, for instance:
let readFile (f: string) =
try
new StreamReader(f)
|> Seq.unfold
(fun reader ->
try
if not reader.EndOfStream then
Some(reader.ReadLine(), reader)
else
reader.Dispose()
None
with ex ->
printfn "Exception while reading line: %O" ex
reader.Dispose()
None)
with ex ->
printfn "Exception while opening the file: %O" ex
Seq.empty
Perhaps a less tricky approach would be to wrap StreamReader.ReadLine so that it doesn't throw exceptions. That way you can still use a seq expression and a use statement.
let readLine (reader: StreamReader) =
try
reader.ReadLine() |> Some
with ex ->
printfn "Exception while reading line: %O" ex
None
let readFile2 (f: string) =
try
let r = new StreamReader(f)
seq {
use reader = r
let mutable error = false
while not error && not reader.EndOfStream do
let nextLine = readLine reader
if nextLine.IsSome then yield nextLine.Value else error <- true
}
with ex ->
printfn "Exception while opening the file: %O" ex
Seq.empty
let readFile (f : string) =
try File.ReadLines(f)
with ex -> printfn "Exception: %s" ex.Message; Seq.empty

F# / Argu - How to display help for two level command tree without throwing exception

I have a two-level F# / Argu command tree. Its abbreviated version looks like that:
[<CliPrefix(CliPrefix.Dash)>]
type RunContGenArgs =
| [<Unique>] [<EqualsAssignment>] [<AltCommandLine("-ql")>] MaxQueueLength of int
with
interface IArgParserTemplate with
member this.Usage =
match this with
| MaxQueueLength _ -> "max queue length."
and
[<CliPrefix(CliPrefix.None)>]
ContGenArguments =
| [<Unique>] [<AltCommandLine("run")>] RunContGen of ParseResults<RunContGenArgs>
with
interface IArgParserTemplate with
member this.Usage =
match this with
| RunContGen _ -> "run Continuous Generation."
which, I then use as follows:
[<EntryPoint>]
let main argv =
let parser = ArgumentParser.Create<ContGenArguments>(programName = "ContGen.exe")
let results = parser.Parse argv
match results.GetAllResults() |> ContGenTask.tryCreate with
| Some task -> task.run()
| None ->
printfn "%s" (parser.PrintUsage())
-1
If I run the command like ContGen.exe run help, then it correctly displays help for the command run. However, it then crashes with ugly exception:
Unhandled Exception: Argu.ArguParseException: USAGE: ContGen.exe runcontgen [help] [-maxqueuelength=<int>]
OPTIONS:
-maxqueuelength, -ql=<int>
max queue length.
help display this list of options.
at Argu.ExceptionExiter.Argu-IExiter-Exit[a](String msg, ErrorCode errorCode) in C:\Users\eirik.tsarpalis\devel\public\Argu\src\Argu\Types.fs:line 62
at Argu.ArgumentParser\`1.Parse(FSharpOption\`1 inputs, FSharpOption\`1 configurationReader, FSharpOption\`1 ignoreMissing, FSharpOption\`1 ignoreUnrecognized, FSharpOption\`1 raiseOnUsage) in C:\Users\eirik.tsarpalis\devel\public\Argu\src\Argu\ArgumentParser.fs:line 180
at Program.main(String[] argv) in C:\GitHub\ClmFSharp\Clm\ContGen\Program.fs:line 8
If I change let results = parser.Parse argv into let results = parser.Parse(argv, raiseOnUsage = false), then it does not crash but does not display any help message. And then since command run can run without any second level argument, the program just keeps going instead of displaying help and quitting.
However, I need ContGen.exe run help just display help message and then quit. How can I achieve that? Thanks.
This is a somewhat peculiar behavior of Argu; you need to provide your own exiter to avoid the exception being thrown there.
Something along these lines:
type NonThrowingExiter() =
interface IExiter with
member __.Name = "Exiter" // I don't know what this is used for; I have never seen it appear anywhere
member __.Exit (msg, code) =
if code = ErrorCode.HelpText then
printfn "%s" msg
exit 0
else
printfn "%s" msg // Maybe have code to color the console output red here
exit 1
To use this, create your `ArgumentParser` like this:
let argumentParser =
Argu.ArgumentParser.Create<ContGenArguments>(helpTextMessage = "Help requested",
errorHandler = NonThrowingExiter())
(You don't actually need to create a class for this, of course; an object expression will do it just as well.)

Type test pattern matching for DUs

With DU (Discriminated Union types), how do I perform a type test pattern matching ?
I have this following running code :
type IU =
|Int of int
|Unit of Unit
let x = IU.Int(3)
let y = IU.Unit(())
let z = [3.14]
let showI (v) =
match box v with
| :? IU ->
match v with
| Int(_) -> "an IU int"
|_ -> "not a IU.int"
|_ -> "not a IU.int"
But I am not happy with the inner match in the showI function. I would have preferred something like :
let showI (v) =
match box v with
| :? IU.Int -> "an int"
|_ -> "not a IU.int"
which doesn't compile (error : the type Int is not defined).
Is there an obvious syntax I missed ? Thanks.
Note : showI function accepts a variable with an unknowned type ; that is the reason for the smelly box v.
As others have pointed out, I don't think there's any built-in language feature that lets you do this. However, you could define an active pattern that performs the type test:
let (|IsIU|_|) (candidate : obj) =
match candidate with
| :? IU as iu -> Some iu
| _ -> None
This active pattern has the type obj -> IU option.
You can compose your own custom active pattern with standard patterns, like this:
let showI = function
| IsIU (IU.Int i) -> "an IU int"
| _ -> "not a IU.int"
In this example, the custom IsIU active pattern has been composed with a standard identifier pattern that matches on the IU.Int case.
Here's a sample FSI session showing usage with the x, y, and z values given in the OP:
> showI x;;
val it : string = "an IU int"
> showI y;;
val it : string = "not a IU.int"
> showI z;;
val it : string = "not a IU.int"
Staying within the context of your question I believe what you are missing is that IU.Int is not a type, but a case Int of discriminated union type IU. When you write
let x = IU.Int(3)
the type of value x is IU, not IU.Int. That's why compiler barks upon your attempt to match obj to UI.Int with :? pattern.
In a broader context, it seems you try approaching F# a-la dynamic language of Javascript kind, which it is not. Exaggerating a bit, you seemingly try using functions operating upon arguments of only one type obj and hence spending substantial run-time effort on dynamic discovery of specific argument types with wide opportunities for making mistakes on the way.
Such approach misses the whole point of F# idiomatic DU use case, which is disassembling of a value that is known to be statically typed as IU by pattern match machinery to specific union case (IU.Int or IU.Unit):
let showI (v : IU) = // explicit argument type is added to illuminate the point
match v with
| IU.Int(x) -> sprintf "a IU.Int(%i) value" x
| _ -> "a IU.Unit"
So, if you by mistake try calling showI with argument that is not of type IU, compiler will catch the erroneous use of your function with argument of wrong type right away and simply will not build the executable form of your code until the mistake is corrected.
EDIT: Idiomatic use aside you may get away with a single match, indeed, with the help of when guard, like in a snippet below, although this is a nasty hack:
open Microsoft.FSharp.Reflection
let showI (v) =
match box v with
| :? IU as x when (fst(FSharpValue.GetUnionFields(x, typeof<IU>))).Name.Equals("Int")
-> "an IU.Int"
| _ -> "not an IU.Int"

How to properly test Exceptions with FsUnit

I'm trying to figure out how to properly test exceptions with FsUnit. Official documentation states, that to test for exceptions I have to right something like this:
(fun () -> failwith "BOOM!" |> ignore) |> should throw typeof<System.Exception>
But, if I don't mark my test method with [<ExpectedException>] attribute it will always fail. Sounds reasonable because if we want to test for exceptions we have to add such attribute in C# + NUnit.
But, as long as I've added this attribute it doesn't matter what kind of exception I'm trying to throw, it will be always handled.
Some snippets:
My LogicModule.fs
exception EmptyStringException of string
let getNumber str =
if str = "" then raise (EmptyStringException("Can not extract number from empty string"))
else int str
My LogicModuleTest.fs
[<Test>]
[<ExpectedException>]
let``check exception``()=
(getNumber "") |> should throw typeof<LogicModule.EmptyStringException>
Answer has been found. To test that exception was thrown I should wrap my function call in the next style:
(fun () -> getNumber "" |> ignore) |> should throw typeof<LogicModule.EmptyStringException>
because underneath #fsunit uses NUnit's Throws constraint
http://www.nunit.org/index.php?p=throwsConstraint&r=2.5 … which takes a delegate of void, raise returns 'a
If you want to test that a specific exception type is raised by some code, you can add the exception type to the [<ExpectedException>] attribute like so:
[<Test; ExpectedException(typeof<LogicModule.EmptyStringException>)>]
let``check exception`` () : unit =
(getNumber "")
|> ignore
More documentation is available on the NUnit site: http://www.nunit.org/index.php?p=exception&r=2.6.2

Dynamic cast to Interface

According to the post http://cs.hubfs.net/forums/thread/3616.aspx,
I need to use a function like the following to cast an object to an interface, I have run a test, this is still true, the bug of :?> is still not fixed.
let cast<'a> o = (box o) :?> 'a
let ci = { new Customer(18, Name = "fred") with
override x.ToString() = x.Name
interface ITalk with
member x.Talk() =
printfn "talk1111111" }
let italk = cast<ITalk> ci
if not (italk = null) then
italk.Talk()
Is there a more elegant way to write the above code. I am thinking to create another operator to replace :?>, but I can not get the generic type parameter passed in like the :?>
Your cast function does not behave like the C# as operator - if the object can't be cast to the specified type, it will throw an exception rather than returning null. Therefore, checking to see if italk = null accomplishes nothing. If you want to make the cast function return null when the cast fails instead of throwing an exception, you could write it like this:
let cast<'a when 'a : null> o =
match box o with
| :? 'a as output -> output
| _ -> null
However, this will only work on nullable types, which does not include structs or (by default) F# types. I might leave your cast function the way it is, and make a tryCast that uses options.
let tryCast<'a> o =
match box o with
| :? 'a as output -> Some output
| _ -> None
Then you could use it like this:
ci |> tryCast<ITalk> |> Option.iter (fun it -> it.Talk())
In this case, Option.iter takes the place of your null test.
Pattern matching provides a more idiomatic way to write this:
match box ci with
| :? ITalk as italk -> italk.Talk()
| _ -> ()
Or, even:
let bci = box ci
if bci :? ITalk then (bci :?> ITalk).Talk()
I keep a function like the following around, for when I know the type test will hold:
let coerce value = (box >> unbox) value
(coerce ci : ITalk).Talk()

Resources