A Monad for COM Interop

Well, I finally got to write my first monad. Seems I am getting the hang of it now. Reading about monads only takes you so far. Its not until you do it yourself that you truly grok monads.

In my case I have a monad implementation to manage COM object references. I am pulling data from Excel into F# for an optimization problem. Excel interaction is via COM. COM requires that if you acquire an object reference then you have to eventually release it. My code was getting messy managing COM object references. Now with a monad managing object references the code ends up being a lot cleaner.

The monad implementation uses F# workflows so that you can write code such as:

com {
let aRange = usedRange.Range(sprintf "%d:%d" 1 1) 
return aRange.Value2 : ?> Object[,] } |> Com.Run

Assuming ‘usedRange’ is a reference to Excel’s used range of cells, the above code will return the values of the entire first row as a multi-dimensional array. The let binding in the ‘com’ monad will automatically release the reference to ‘aRange’ COM object when it goes out of scope. Your code does not have to manage that.

When working with COM avoid ‘dots’ in succession as in:

   let range = usedRange .Find(What="xyz") .Offset(1,1)

instead use:

let r1 = usedRange.Find(What="xyz")
let r2 = r1.Offset(1,1)

With dots in succession, implicit COM references are created that cannot be released as there is no handle to address them. Use a let binding for each new COM object referenced so that it gets released by the monad.

You can download the COM monad from the following link:

https://gist.github.com/736343

About these ads

2 thoughts on “A Monad for COM Interop

  1. Can I use this like next:
    com {
    let usedRange= application.Selection()
    let aRange = usedRange.Range(sprintf “%d:%d” 1 1)
    return aRange.Value2 : ?> Object[,]
    } |> Com.Run

    Will it release usedRange, and release only after usedRange used?

    Is it possible to write similar in C#, is fluent interfaces a way to go?

    • Anytime a COM object is returned you have to use a ‘let’ binding.
      The monad should release anything bound to let xxx = … .
      I think aRange.Value2 does not return a COM object so a let binding is not required.

      Use Task Manager to see if Excel.exe exits after your code finishes (give it about 5 – 10 seconds). If it hangs around then something was not released.

      You may be able to use LINQ expressions in C# but I think the code will end up being much more complex.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s