Search code examples
structf#mutable

Can't Update Mutable Field in Struct?


Can anyone tell me why this Counter struct won't work? It always resets the value to 0 between calls to Incr.

type Counter = 
    struct

        val mutable i: int 

        member public this.Incr() =
            this.i <- this.i + 1

        member public this.Count = 
            this.i
    end

let noCounty(s:string): int = 
    let x = new Counter()
    x.Incr()
    x.Incr()
    x.Count

Solution

  • The semantics of mutable structs is always confusing, because there are situations where the struct is unexpectedly copied when you use it in certain ways - so it is a good idea to avoid mutation inside structs.

    You can make this work by marking the x variable inside noCounty mutable. Given your current definition of Counter, the following works as expected:

    let noCounty() = 
        let mutable x = new Counter()
        x.Incr()
        x.Incr()
        x.Count
    

    I agree this is pretty confusing. I think the logic is that if you define the variable as immutable, then the compiler copies the value of the struct into a new variable before making any call that might mutate it. As a result, the compiled code looks more like:

    let noCounty () = 
        let x = new Counter()
        (let t1 = x in t1.Incr())
        (let t2 = x in t2.Incr())
        (let t3 = x in t3.Count)
    

    I would expect the compiler to give me some warning about this - so perhaps the lack of warning in this case should be reported as a compiler bug. (Though the behaviour is probably intended.)