This past weekend I had the good fortune of speaking about F# at GR DevDay in Grand Rapids, Michigan. As part of this particular talk, I highlight how the F# compiler deals with calls to methods with out parameters. Naturally, this prompted a question about how it handles ref parameters. I don’t use ref parameters very often (ok, ever – I seem to have an aversion to side-effects!) so I had to admit that I’d never given it much thought and couldn’t immediately recall how to do it. I’m here today with the answer to the question.
Consider a C# function with the following signature:
public void DoSomethingWithRefParam(ref int refParam)
Just as with out parameters, F# doesn’t have any direct way to pass arguments by reference. Instead, we need to use a reference cell. Coming from C#, you might think the following F# code would be adequate.
// Bad, does not work let v = 10 x.DoSomethingWithRefParam (ref v)
This code compiles but it’s not quite right. When it executes, any changes that DoSomethingWithRefParam makes to the reference cell will not be reflected in v. Why? Remember, the ref operator creates an instance of FSharpRef<_> which is a type that carries a mutable value. It is the mutable value which is passed by reference to the method. By including the ref operator in the call to DoSomethingWithRefParam as we would in C#, we’re not passing v by reference but instead wrapping the value of v in a reference cell to which we have no reference outside of the method call. To make this code work, we need to change the definition of v as follows:
let v = ref 10 x.DoSomethingWithRefParam v
Now, v is a reference cell and any changes made to its wrapped value in DoSomethingWithRefParam will be reflected whenever we access it later in the code.