Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

use-style binding on a disposable object returned as an option

Tags:

f#

Wondering if there is an elegant way to accomplish the following:

I have a function that creates a Disposable and returns it as an Option. The caller matches on it. Now, since the wrapped object is bound to inside a match case, I don't know how to do a 'use' style binding inside the match such that the object gets properly disposed.

let createSocket (hostEntry:IPHostEntry) =
    let httpPort = 80
    let endpoint = new IPEndPoint(hostEntry.AddressList.[0], httpPort)
    let socket = new Socket(endpoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp)
    socket.Connect(endpoint)
    if (socket.Connected) then Some socket else None

let fetchResource url =
    let uri = new System.Uri(url)
    let hostEntry = Dns.GetHostEntry(uri.Host)
    match createSocket(hostEntry) with
    | Some socket ->
        use s = socket // More elegant way?
        sendRequest s uri.Host uri.PathAndQuery |> getResponse
    | None ->
        "Failed to open socket"
like image 319
sanket patel Avatar asked Jan 29 '17 18:01

sanket patel


2 Answers

You have a using function available in core library, but it's up to you whether you consider this more elegant:

match createSocket(hostEntry) with
| Some socket ->
    using socket <| fun s ->
        sendRequest s uri.Host uri.PathAndQuery |> getResponse
| None ->
    "Failed to open socket"

You can take it a step further and package the whole trick in a single function:

module Option =     
    let using func = Option.bind (fun disp -> using disp func)

...

createSocket(hostEntry)
|> Option.using (fun s ->
    sendRequest s uri.Host uri.PathAndQuery |> getResponse)
// handle None however you like
|> function Some x -> x | None -> "Failed to open socket" 

Though I don't remember I've ever felt the need to do so personally.

like image 194
scrwtp Avatar answered Nov 04 '22 16:11

scrwtp


I think null is most elegant here.

if socket.Connected then socket else null

...

use s = createSocket(hostEntry)
if s = null then
    "Failed..."
else
    sendRequest...

use can properly handle (ignore) null. That said, I didn't find the original code particularly inelegant to start.

like image 45
Brian Avatar answered Nov 04 '22 16:11

Brian