Exceptions: The try...finally Expression

The try...finally expression enables you to execute clean-up code even if a block of code throws an exception.

Syntax

try
    expression1
finally
    expression2

Remarks

The try...finally expression can be used to execute the code in expression2 in the preceding syntax regardless of whether an exception is generated during the execution of expression1.

The type of expression2 does not contribute to the value of the whole expression; the type returned when an exception does not occur is the last value in expression1. When an exception does occur, no value is returned and the flow of control transfers to the next matching exception handler up the call stack. If no exception handler is found, the program terminates. Before the code in a matching handler is executed or the program terminates, the code in the finally branch is executed.

The following code demonstrates the use of the try...finally expression.

let divide x y =
   let stream : System.IO.FileStream = System.IO.File.Create("test.txt")
   let writer : System.IO.StreamWriter = new System.IO.StreamWriter(stream)
   try
      writer.WriteLine("test1")
      Some( x / y )
   finally
      writer.Flush()
      printfn "Closing stream"
      stream.Close()

let result =
  try
     divide 100 0
  with
     | :? System.DivideByZeroException -> printfn "Exception handled."; None

The output to the console is as follows.

Closing stream
Exception handled.

As you can see from the output, the stream was closed before the outer exception was handled, and the file test.txt contains the text test1, which indicates that the buffers were flushed and written to disk even though the exception transferred control to the outer exception handler.

Note that the try...with construct is a separate construct from the try...finally construct. Therefore, if your code requires both a with block and a finally block, you have to nest the two constructs, as in the following code example.

exception InnerError of string
exception OuterError of string

let function1 x y =
   try
     try
        if x = y then raise (InnerError("inner"))
        else raise (OuterError("outer"))
     with
      | InnerError(str) -> printfn "Error1 %s" str
   finally
      printfn "Always print this."


let function2 x y =
  try
     function1 x y
  with
     | OuterError(str) -> printfn "Error2 %s" str

function2 100 100
function2 100 10

In the context of computation expressions, including sequence expressions and async expressions, try...finally expressions can have a custom implementation. For more information, see Computation Expressions.

See also