Defer in F#

Our example demonstrates the use of the use keyword in F#, which is similar to the defer concept in other languages. It ensures that a resource is properly disposed of when it goes out of scope.

open System
open System.IO

// Suppose we wanted to create a file, write to it,
// and then close when we're done. Here's how we could
// do that with `use`.
let main() =
    // The `use` keyword ensures that the file is closed
    // when it goes out of scope, similar to `defer` in other languages.
    use f = createFile "/tmp/defer.txt"
    writeFile f

and createFile (path: string) =
    printfn "creating"
    try
        new StreamWriter(path)
    with
    | ex -> 
        failwithf "Failed to create file: %s" ex.Message

and writeFile (writer: StreamWriter) =
    printfn "writing"
    writer.WriteLine("data")

// It's important to handle exceptions when closing a file,
// even in a `use` block.
// The `use` keyword automatically calls Dispose on IDisposable objects,
// which includes closing for StreamWriter.

[<EntryPoint>]
let entryPoint _ =
    main()
    0

Running the program confirms that the file is created, written to, and then closed:

$ dotnet run
creating
writing

In F#, we use the use keyword to ensure that disposable resources (like files) are properly cleaned up. This is similar to the defer concept in other languages, but it’s more idiomatic to F# and .NET.

The use keyword automatically calls the Dispose method on the object when it goes out of scope, which for a StreamWriter includes closing the file. This happens even if an exception is thrown, ensuring that resources are always properly cleaned up.

Note that in F#, we don’t need to explicitly close the file as we do in some other languages, because the use keyword takes care of that for us. However, it’s still a good practice to handle any exceptions that might occur during file operations.