Reputation: 1610
I would like to have a mutable state in an F# object expression. The first approach is to use ref cells as follows:
type PP =
abstract member A : int
let foo =
let a = ref 0
{ new PP with
member x.A =
let ret = !a
a := !a + 1
ret
}
printfn "%A" foo.A
printfn "%A" foo.A
printfn "%A" foo.A
printfn "%A" foo.A
A different approach would be as follows:
type State(s : int) =
let mutable intState = s
member x.state
with get () = intState
and set v = intState <- v
[<AbstractClass>]
type PPP(state : State) =
abstract member A : int
member x.state
with get () = state.state
and set v = state.state <- v
let bar n =
{ new PPP(State(n)) with
member x.A =
let ret = x.state
x.state <- ret + 1
ret
}
let barA1 = bar 0
printfn "%A" barA1.A
printfn "%A" barA1.A
printfn "%A" barA1.A
printfn "%A" barA1.A
Which version would be likely more performing (I need the state updating x.state <- ret + 1 in performance critical sections)? My guess is that the State object is also allocated on the heap so there is no reason why the second version should be faster. However it is slightly more appealing to use.
Thanks for any feedback and suggestions
Upvotes: 2
Views: 586
Reputation: 243051
As Daniel said, the last approach is essentially equivalent to using built-in ref
.
When using ref
, you're allocating two objects - the one that you're returning and the reference cell itself. You can reduce this to just a single allocated object by using a concrete implementation (but I don't think this will matter in practice):
type Stateful(initial:int) =
let mutable state = initial
interface PP with
member x.A =
let ret = state
state <- state + 1
ret
let foo =
Statefull(0) :> PP // Creates a single object that keeps the state as mutable field
Aside, you are using read-only property that modifies internal state of the object and returns a new state each time. This is a dangerous pattern that could be quite confusing - properties with getter shouldn't modify the state, so you should probably use a method (unit -> int
) instead.
Upvotes: 5
Reputation: 47904
Your State
class is identical to ref
. They're both reference types (you can't capture a mutable value type from an object expression). I would prefer a built-in type when possible. ref
is the idiomatic way to represent a heap-allocated mutable value.
If ever in doubt about performance, benchmark it.
Upvotes: 3