Go Functional Go Functional - 9 months ago 56
C# Question

Interop with parameters passed by ref

I'm trying to call a C# function of an already existing library (and I don't have time to port the whole library to F#)

namespace ExportLib

public static class Xlsx
public static bool TestSave(string proposed, ref string filename, ref string save_log) {

from an F# code

let getUserFile(proposed) : UserFile =
let mutable filename = ""
let mutable save_log = ""
match Xlsx.TestSave(proposed, ref filename, ref save_log) with
| true -> FileResult(filename)
| false -> ErrorMsg(save_log)

meant to transform the function into algebraic data types with the objective to make illegal states unrepresentable.

type UserFile =
// The value here is the file path.
| FileResult of string
// The value here is the error msg.
| ErrorMsg of string

My issue is that the
remains unchanged despite it is assigned in the C# function (same problem with
out string
instead of
ref string

Answer Source

In F# ref is not a keyword but a function creating a reference cell. Xlsx.TestSave(proposed, ref filename, ref save_log) thus passes two newly created reference cells (pointing to mutable string values) into TestSave which in turn changes the ref cell to point to whatever string is assigned. Unfortunately, this is not observable from the outside, as there's nothing pointing to the ref cells. The correct approach is:

let getUserFile(proposed) : UserFile =
   let filename = ref ""
   let save_log = ref ""
   match Xlsx.TestSave(proposed, filename, save_log) with
   | true -> FileResult(!filename)
   | false -> ErrorMsg(!save_log)