Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / All-Topics

F#19 : Exceptions

0.00/5 (No votes)
17 Apr 2014CPOL7 min read 16.3K  
In this post we will look at how to handle exceptions.

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.

image

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:

image

 

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

    //should work
    let result = getListItem 2 [1..10]
    printfn "result was %A" result

    //should not work, argument out of bounds
    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

image

 

 

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:

image

 

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#.

 

PatternDescription
? exception-typeMatches the specified .NET exception type.
:? exception-type as identifierMatches the specified .NET exception type, but gives the exception a named value.
exception-name(arguments)Matches an F# exception type and binds the arguments.
identifierMatches any exception and binds the name to the exception object. Equivalent to :? System.Exception as identifier
identifier when conditionMatches 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:

image

 

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

image

 

 

 

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:

 

image

 

 

 

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() rethrows exception back ut again
            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:

image

 

 

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:

image


License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)