Exceptions

Use exceptions for unexpected failures and .NET interop. Use Result/Option for expected, domain-level failures.

// Raising
failwith "Something went wrong"                         // System.Exception
failwithf "Invalid value: %d" 42
invalidArg "age" "Age must be positive"                 // ArgumentException
invalidOp "Operation not allowed"                       // InvalidOperationException
nullArg "name"                                          // ArgumentNullException
raise (System.IO.FileNotFoundException "missing.txt")

// Custom F# exceptions
exception InsufficientFunds of needed: decimal * available: decimal

let withdraw balance amount =
    if amount > balance then raise (InsufficientFunds (amount, balance))
    balance - amount

// Handling
let safeWithdraw balance amount =
    try
        Ok (withdraw balance amount)
    with
    | InsufficientFunds (needed, available) -> Error $"Need {needed - available} more"
    | :? System.ArgumentException as ex -> Error ex.Message
    | ex -> Error $"Unexpected: {ex.Message}"

// try/finally and use (IDisposable)
let readFirstLine path =
    use reader = new System.IO.StreamReader(path: string)   // disposed at the end of scope
    reader.ReadLine()

try
    printfn "work"
finally
    printfn "cleanup"

// reraise() preserves the stack trace 
…