Reputation: 3509
I'm working with an extern
DLL that has a bunch of routines that return a ReturnCode
enum, so I wrote the following helper function to log all the errors:
let mutable LastError = ReturnCode.OK
let mutable LastReturnCode = ReturnCode.OK
let mutable TotalErrors = 0
let Run (call: unit -> ReturnCode) =
LastReturnCode <- call()
if LastReturnCode <> ReturnCode.OK then
LastError <- LastReturnCode
TotalErrors <- TotalErrors + 1
Great, except some of the DLL's functions have out
parameters. So now when I do something like
let CreateEvfImageRef (streamHandle: int) =
let mutable evfImageHandle = 0
Run (fun () -> Extern.EdsCreateEvfImageRef (streamHandle, &evfImageHandle))
evfImageHandle
the compiler gives me a "mutable variables cannot be captured by closures" error. Is there anything I can do beyond inlining Run
everywhere? This worked fine in C#.
(Example extern declaration below)
[<DllImport(EDSDKPath)>]
extern ReturnCode EdsCreateEvfImageRef(int inStreamHandle, [<Out>] int& outEvfImageHandle);
Upvotes: 3
Views: 1122
Reputation: 243096
You should still be able to use the ref
type, but you do not need to write the &
symbol when passing the reference to the function - the compiler will do this automatically:
let CreateEvfImageRef (streamHandle: int) =
let mutable evfImageHandle = ref 0
Run (fun () -> Extern.EdsCreateEvfImageRef (streamHandle, evfImageHandle))
!evfImageHandle
Upvotes: 6
Reputation: 25526
The standard solution is to use references - the code becomes
let CreateEvfImageRef (streamHandle: int) =
let evfImageHandle = ref 0
Run (fun () -> Extern.EdsCreateEvfImageRef (streamHandle, &(!evfImageHandle)))
!evfImageHandle
However this won't work as the compiler requires !evfImageHandle
to be mutable, which it isn't.
I think the real solution here is to change your Run
function so that it does not take a closure, rather have it take just the return value - which will at least have it work in this case. Then the code becomes
let Run (call: ReturnCode) =
LastReturnCode <- call
if LastReturnCode <> ReturnCode.OK then
LastError <- LastReturnCode
TotalErrors <- TotalErrors + 1
and the code changes to
let CreateEvfImageRef (streamHandle: int) =
let mutable evfImageHandle = 0
Extern.EdsCreateEvfImageRef (streamHandle, &evfImageHandle)) |> Run
evfImageHandle
Or the even more hackish solution. Use the fact that array members are mutable and can be captured by closures to do
let CreateEvfImageRef (streamHandle: int) =
let evfImageHandle = [|0|]
Run (fun () -> EdsCreateEvfImageRef (streamHandle, &(evfImageHandle.[0])) )
evfImageHandle.[0]
Upvotes: 3