Search code examples
f#computation-expression

F# computation expressions


During my learning about computation expressions I've encountered with this method. I understand the logic of it. My question is about the # in the method parameter. What's its purpose? When it's removed, it changes the function signature, but doesn't change the result. Taken from here: https://fsharpforfunandprofit.com/posts/computation-expressions-builder-part6/#complete-code-without-tracing

member this.Using(disposable:#System.IDisposable, body) =
    let body' = fun () -> body disposable
    this.TryFinally(body', fun () ->
        match disposable with
            | null -> ()
            | disp -> disp.Dispose())

Solution

  • As others have mentioned, this is a flexible type, which is broadly equivalent to 'a when 'a :> IDisposable. In other words, "any concrete type that implements IDisposable". It is in fact important in this case, and just using IDisposable is not equivalent.

    The difference becomes apparent if we put the full type signatures equivalent for #IDisposable:

    member this.Using<'a, 'b when 'a :> IDisposable>(disposable:'a, body: 'a -> 'b) =
        // ...
    

    Contrast with the full signature for just IDisposable:

    member this.Using<'b>(disposable: IDisposable, body: IDisposable -> 'b) =
        // ...
    

    The important difference is the type of the argument to body. This determines the type of x in use x = disposable. It needs to be the actual concrete type of disposable, and not just IDisposable. Otherwise, something like this would fail:

    yourCE {
        use f = new StreamReader("file.txt")
        return f.ReadToEnd()   // error FS0039: The type 'IDisposable' does not define the field, constructor or member 'ReadToEnd'
    }