As I discussed it in post f# essential - part 5 - mutable, ref, ref record is used for closure. And mutable is similar concept of variable in c#. So that you can not use mutable defined outside of a function. So the following it is wrong
let build_t() =
let mutable x = 0
let t() =
x <- 1 + x
printfn "you call me %i time(s)" x
t
let t = build_t()
t()
You have to convert it ref record type like the following.
let build_t() =
let x = ref 0
let t() =
x := 1 + !x
printfn "you call me %i time(s)" !x
t
If we define method in a class using F#, and we want to update the member field in a method, should we also use mutable or ref record. It turns out, both of them are supported.
type Foo() =
let mutable callT1Count = 0
let callT2Count = ref 0
member x.t1() =
callT1Count <- callT1Count + 1
printfn "you call t1 %i time(s)" callT1Count
member x.t2() =
callT2Count := !callT2Count + 1
printfn "you call t2 %i time(s)" !callT2Count
let f = new Foo()
f.t1()
f.t2()
I used reflector to decompile it to c# code as follow to know that that is implemented in .net
[Serializable, CompilationMapping(SourceConstructFlags.ObjectType)]
public class Foo
{
// Fields
internal int callT1Count = 0;
internal FSharpRef<int> callT2Count = Operators.Ref<int>(0);
// Methods
public void t1()
{
this.callT1Count++;
FSharpFunc<int, Unit> func = ExtraTopLevelOperators.PrintFormatLine<FSharpFunc<int, Unit>>(new PrintfFormat<FSharpFunc<int, Unit>, TextWriter, Unit, Unit, int>("you call t1 %i time(s)"));
int num = this.callT1Count;
func.Invoke(num);
}
public void t2()
{
Operators.op_ColonEquals<int>(this.callT2Count, Operators.op_Dereference<int>(this.callT2Count) + 1);
FSharpFunc<int, Unit> func = ExtraTopLevelOperators.PrintFormatLine<FSharpFunc<int, Unit>>(new PrintfFormat<FSharpFunc<int, Unit>, TextWriter, Unit, Unit, int>("you call t2 %i time(s)"));
int num = Operators.op_Dereference<int>(this.callT2Count);
func.Invoke(num);
}
}
Why mutable is not supported in closure? I think the reason is that when you create an instance of Class, the variable (mutable) is already closed in an instance. Of course, ref type is still supported, but but I think it is double closed. We only need to use variable(mutable) in class.