Go Functional Go Functional - 20 days ago 7
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
mutable
F#
filename
remains unchanged despite it is assigned in the C# function (same problem with
out string
instead of
ref string
)

Answer

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)