In this post we will look at how to handle exceptions. We will be covering the following areas
- Using the standard F# helper functions
- Try With
- Try Finally
- Raising Exceptions
- Reraising Exceptions
- Custom Exceptions
FailWith
Probably the easiest path into Exception handling in F# is by using the helper function “failwith”, which when used produces pre-canned Microsoft.FSharp.Core.FailureException where your code is able to supply the Exception message. Here is an example of how to use this:
let divideByZeroFailwith x y =
if (y = 0) then failwith "Oh no can't divide by zero silly"
else
x / y
let result1 = divideByZeroFailwith 10 0
If you run this code though you will see an issue, can you spot it?
So we just said the failwith helper function raises a new Microsoft.FSharp.Core.FailureException but this code doesn’t catch the exception so this code as it stands would cause the application to crash, as shown below.
So what do we need to do to fix this? Simply really we just need to catch the exception. Here is the same code refactored to catch the exception.
let divideByZeroFailwith x y =
if (y = 0) then failwith "Oh no can't divide by zero silly"
else
x / y
try
divideByZeroFailwith 100 0
with
| Failure(msg) -> printfn "%s" msg; 0
Which when run gives the following output:
We will be looking at catching Exceptions in detail later in this blog.
InvalidArg
F# also comes with another helper function for raising an System.ArgumentException, which is the “invalidArg” function, which you can see an example of shown below.
This example allows the calling code to get an element value from a list using an index position, but if the requested index position is out of bounds (I am naively only checking the lower bound) we will get a System.ArgumentException thrown thanks to the usage of the invalidArg function
This example goes a little bit far for right now, but it does show you how you can catch a certain type of Exception, and get its message out within the with block. As I say we will be looking at this in this blog post, so don’t panic just yet if you do not get what the “| :?” syntax is doing.
let getListItem index (theList :int list) =
if index < 0
then invalidArg "index" "Index is out of range"
List.nth theList index
try
let result = getListItem 2 [1..10]
printfn "result was %A" result
let result = getListItem -1 [1..10]
printfn "result was %A" result
with
| :? System.ArgumentException as ex -> printfn "%s" ex.Message;
When run this produces the following output
Try With
In F# we can use the “try..with”expression to handle exceptions. One thing to note is that the “try..with” expression returns a value. Frequently, the fact that an error occurred also means that there is no valid value that can be returned from the expressions in each exception handler. As such a lot of people will use an option type. The option type MUST be the same type as the one in the try block. Here is an example
let optionReturningDivide x y =
try
Some( x / y )
with
| :? System.DivideByZeroException as ex -> printfn "Exception! %s " (ex.Message); None
let printIt opt =
match opt with
| Some(i) -> printfn "Result was %A" i
| None -> printfn "It was bad"
let resultGood = optionReturningDivide 10 2
do printIt resultGood
let resultBad = optionReturningDivide 10 0
do printIt resultBad
Which when run gives the following results:
There are a couple of points to note in this latest snippet, which are
- We used an Option type as the return value from a function that had a try..with block in it, which allows us to return a “Good value i.e. : Some(..)” or a “Bad value i.e. : None”, which can be pattern matched against by the caller
- That we used the “| :?” syntax again. This is a pattern match used with a cast operator to cast the exception to a known type.
The first of those points should make sense, since we have covered option types and pattern matching, but the second point, may need a bit more explaining.
So when you have used a try..with block you are able to filter out what type of exception you want to deal with. Exceptions may be .NET exceptions or F# exceptions (which are created using the F# exception keyword, more on this later). Generally speaking this table tells you what you can do with filtering exceptions in F#.
Pattern | Description |
? exception-type | Matches the specified .NET exception type. |
:? exception-type as identifier | Matches the specified .NET exception type, but gives the exception a named value. |
exception-name(arguments) | Matches an F# exception type and binds the arguments. |
identifier | Matches any exception and binds the name to the exception object. Equivalent to :? System.Exception as identifier |
identifier when condition | Matches any exception if the condition is true. |
We have already covered a couple of items in that table in the examples we have seen so far, and we should see an example of one or 2 more of them by the time we finish this post.
Try Finally
The try..finally expression allows you to run code even if a block of code throws an exception. Here is a trivial example
let someArbitaryFinallyFunction x y =
try
x / y
finally
printfn "finally called in someArbitaryFinallyFunction" |> ignore
let getResult x y =
try
Some(someArbitaryFinallyFunction x y)
with
| :? System.DivideByZeroException as ex -> printfn "Exception! %s " (ex.Message); None
printfn "(getResult 10 2) = %A\r\n" (getResult 10 2)
printfn "(getResult 10 0) = %A\r\n" (getResult 10 0)
Which gives the following output:
One common area where you may want to use try..finally is to handle the disposal of a resource. Here is an example of that
let writeToFileTest =
let stream : System.IO.FileStream = System.IO.File.Create("test.txt")
let writer : System.IO.StreamWriter = new System.IO.StreamWriter(stream)
try
writer.WriteLine("in the file")
finally
writer.Flush()
printfn "Closing stream"
stream.Dispose()
Although not directly related to try..finally, since we just talked about IDisposable it seems like it may be an ok place, so show an example or 2 of alternative approaches you could use in F# for handling IDisposable types.
The first way is by using the use binding, which is similar to the let binding but adds a call to dispose on the value when the value goes out of scope.
let writeToFileTest =
use file1 = File.CreateText("test.txt")
file1.WriteLine("in the file")
Another way is to use the using function. Which works much the same as it does in C#, the only difference is that in F# the disposable value becomes an input parameter to a lambda. At the end of the lambda the runtime calls the dispose method for you. Here is an example
let writeToFileTest =
using(File.CreateText("test.txt"))
(fun theFile -> theFile.WriteLine("in the file"))
Sorry about that slight off topic discussion, it just seemed to fit quite well with the current try..finally discussion, so apologies again for slipping that in there.
Combining Try..With / Try..Finally
The try with and try finally are separate, and can’t be created as a single statement, you are however free to nest them as your requirement dictate. Here is a small example:
let printIt opt =
match opt with
| Some(x) -> printfn "Result was %A" x
| None -> printfn "None"
let optionReturningCombinedTryWithFinallyDivide x y =
try
try
Some( x / y )
with
| :? System.DivideByZeroException as ex -> printfn "Exception! %s " (ex.Message); None
finally
printfn "I am the finaly block" |> ignore
let resultGood = optionReturningCombinedTryWithFinallyDivide 10 2
do printIt resultGood
let resultBad = optionReturningCombinedTryWithFinallyDivide 10 0
do printIt resultBad
Which when run produces this output
Raising Exceptions
You can also raise exceptions using the raise function, which can be applied to .NET Exceptions and F# custom exceptions. Here is a small example
let printIt opt =
match opt with
| Some(x) -> printfn "Result was %A" x
| None -> printfn "None"
let raisingFunction x y =
if y = 0 then raise (new DivideByZeroException("y was zero, not going to work"))
else
Some( x / y )
let consumingFunction x y =
try
let resultGood = raisingFunction x y
do printIt resultGood
with
| :? System.DivideByZeroException as ex ->
printfn "Handled %s " (ex.Message);
do consumingFunction 10 2
do consumingFunction 10 0
Which when run gives the following output:
Reraising Exceptions
Another very common thing you may want to do is to re-throw an exception. In C# this would be accomplished using “throw;” inside of catch block, if you wanted to preserve original stack trace. F# can do the same it is just that the way you do it is slightly different.
In F# you need to use the reraise function inside a catch block. Here is an example where we have a function that uses a try..with, but also uses the reraise() function to rethrow the exception that the outer (consuming function) deals with i its own try..with block.
let printIt opt =
match opt with
| Some(x) -> printfn "Result was %A" x
| None -> printfn "None"
let reraisingFunction x y =
try
Some( x / y )
with
| :? System.DivideByZeroException as ex ->
printfn "Inner handled %s " (ex.Message);
reraise()
let outerHandler x y =
try
let resultGood = reraisingFunction x y
do printIt resultGood
with
| :? System.DivideByZeroException as ex ->
printfn "Outer handled %s " (ex.Message);
do outerHandler 10 2
do outerHandler 10 0
Which when run gives the following output:
Custom Exceptions
So far we have seen how to use the F# helper functions, and catch standard .NET exceptions, but what about when you want to create your own Exceptions, what choices do you have. Well you have 2 actually :
- Inherit from the standard .NET exception classes such as ApplicationException etc etc
- Use F# Exceptions.
It is the later point that the rest of this post will concentrate on, as we will cover inheritance in a later post n this series.
So how do we create and use our own F# exception types? Well it is actually pretty simple we just use the exception F# keyword, and then we can declare a new type and treat it as a catchable exception. Here is an example:
This is how we declare a new F# exception type (see the exception keyword in use there). It can be seen that we can create this type exactly how we want to.
exception MyFSharpException1 of string * int
And here is the consuming code, notice the following:
- We do NOT need to do the casting anymore, we can just deal with the F# exception how we would any other F# type and do cool things like pattern match its internal tupled structure. Neato
- We were able to use the raise keyword to throw this exception type too, just as we did with the standard .NET ones
let printIt opt =
match opt with
| Some(x) -> printfn "Result was %A" x
| None -> printfn "None"
let raisingFunction x y =
if y = 0 then raise (MyFSharpException1 ("y was zero, not going to work",1))
else
Some( x / y )
let consumingFunction x y =
try
let resultGood = raisingFunction x y
do printIt resultGood
with
| MyFSharpException1 (msg, failcount) ->
printfn "Handled : msg : %A, Failcount: %A " msg failcount;
do consumingFunction 10 2
do consumingFunction 10 0
And this is what it looks like when it runs: