Exceptions: The try...with Expression

This topic describes the try...with expression, the expression that is used for exception handling in F#.


| pattern1 -> expression2
| pattern2 -> expression3


The try...with expression is used to handle exceptions in F#. It is similar to the try...catch statement in C#. In the preceding syntax, the code in expression1 might generate an exception. The try...with expression returns a value. If no exception is thrown, the whole expression returns the value of expression1. If an exception is thrown, each pattern is compared in turn with the exception, and for the first matching pattern, the corresponding expression, known as the exception handler, for that branch is executed, and the overall expression returns the value of the expression in that exception handler. If no pattern matches, the exception propagates up the call stack until a matching handler is found. The types of the values returned from each expression in the exception handlers must match the type returned from the expression in the try block.

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. A frequent pattern is to have the type of the expression be an option type. The following code example illustrates this pattern.

let divide1 x y =
      Some (x / y)
      | :? System.DivideByZeroException -> printfn "Division by zero!"; None

let result1 = divide1 100 0

Exceptions can be .NET exceptions, or they can be F# exceptions. You can define F# exceptions by using the exception keyword.

You can use a variety of patterns to filter on the exception type and other conditions; the options are summarized in the following table.

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 asidentifier
identifier when condition Matches any exception if the condition is true.


The following code examples illustrate the use of the various exception handler patterns.

// This example shows the use of the as keyword to assign a name to a
// .NET exception.
let divide2 x y =
    Some( x / y )
    | :? System.DivideByZeroException as ex -> printfn "Exception! %s " (ex.Message); None

// This version shows the use of a condition to branch to multiple paths
// with the same exception.
let divide3 x y flag =
     x / y
     | ex when flag -> printfn "TRUE: %s" (ex.ToString()); 0
     | ex when not flag -> printfn "FALSE: %s" (ex.ToString()); 1

let result2 = divide3 100 0 true

// This version shows the use of F# exceptions.
exception Error1 of string
exception Error2 of string * int

let function1 x y =
      if x = y then raise (Error1("x"))
      else raise (Error2("x", 10))
      | Error1(str) -> printfn "Error1 %s" str
      | Error2(str, i) -> printfn "Error2 %s %d" str i

function1 10 10
function1 9 2


The try...with construct is a separate expression from the try...finally expression. Therefore, if your code requires both a with block and a finally block, you will have to nest the two expressions.


You can use try...with in async expressions, task expressions, and other computation expressions, in which case a customized version of the try...with expression is used. For more information, see Async Expressions, Task Expressions, and Computation Expressions.

See also