Exceptions: The try...with Expression (F#)

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

try
 expression1
with
  | pattern1 -> expression2
  | pattern2 -> expression3
  ...

Remarks

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 =
   try
      Some (x / y)
   with
      | :? 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 as identifier

identifier when condition

Matches any exception if the condition is true.

Examples

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 =
  try
    Some( x / y )
  with
    | :? 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 =
  try
     x / y
  with
     | 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 =
   try 
      if x = y then raise (Error1("x"))
      else raise (Error2("x", 10))
   with
      | Error1(str) -> printfn "Error1 %s" str
      | Error2(str, i) -> printfn "Error2 %s %d" str i

function1 10 10
function1 9 2

Note

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.

Note

You can use try...with in asynchronous workflows and other computation expressions, in which case a customized version of the try...with expression is used. For more information, see Asynchronous Workflows (F#), and Computation Expressions (F#).

See Also

Reference

Exception Types (F#)

Exceptions: The try...finally Expression (F#)

Other Resources

Exception Handling (F#)