Question

I have an F# 3.0 agent wrapped in a class:

type AgentWrapper() =
    let myAgent = Agent.Start(fun inbox ->
            let rec loop (state: int) =
                async {
                    let! (replyChannel: AsyncReplyChannel<int>) = inbox.Receive()
                    let newState = state + 1
                    replyChannel.Reply newState
                    return! loop newState
                }
            loop 0 )

    member private this.agent = myAgent

    member this.Send () = 
        this.agent.PostAndReply (fun replyChannel -> replyChannel)

When I send messages to it as follows:

let f = new AgentWrapper ()
f.Send () |> printf "Reply: %d\n"
f.Send () |> printf "Reply: %d\n"
f.Send () |> printf "Reply: %d\n"

I get the expected responses:

Reply: 1
Reply: 2
Reply: 3

However, if I remove the let binding for the agent and directly assign it to the this.agent property:

type AgentWrapper() =

    member private this.agent = Agent.Start(fun inbox ->
            let rec loop (state: int) =
                async {
                    let! (replyChannel: AsyncReplyChannel<int>) = inbox.Receive()
                    let newState = state + 1
                    replyChannel.Reply newState
                    return! loop newState
                }
            loop 0 )

    member this.Send () = 
        this.agent.PostAndReply (fun replyChannel -> replyChannel)

I then get the responses:

Reply: 1
Reply: 1
Reply: 1

I've been staring at this for hours and I can't understand why the agent is getting re-initialised every time I call AgentWrapper.Send. It feels like this.agent is getting reassigned every time I call it (i.e. acting like a method, not a property). What am I missing?

Was it helpful?

Solution

It feels like this.agent is getting reassigned every time I call it (i.e. acting like a method, not a property). What am I missing?

This is exactly what happens, and is documented in the spec (relevant part from 18.13.1 follows)

Static and instance property members are evaluated every time the member is invoked. For example, in the following, the body of the member is evaluated each time C.Time is evaluated:

type C () =

static member Time = System.DateTime.Now

This is analgous to your situation

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top