10

In C# ReceiveActors I can just have state as private fields in the class. How should I do this in an idiomatic way with the F# API?

Is this a good idea? Any alternatives?

let handleMessage (mailbox: Actor<'a>) msg =
    let mutable i = 1
    match msg with
    | Some x -> i <- i + x
    | None -> ()
Iain
  • 2,500
  • 1
  • 20
  • 24
  • Not what you're looking for, but for [F# agents, the idiomatic approach is to use a recursive loop to carry the state](https://msdn.microsoft.com/en-us/library/ee370357.aspx). However, if Akka.NET forces you down the mutation-oriented path, it may prove impossible to do it 'nicely'. Can you implement an actor for Akka.NET in other ways than deriving from `ReceiveActor`? Something that'd enable you to use a recursive poll loop? – Mark Seemann Mar 17 '15 at 14:43
  • 1
    BTW, if there's another idiomatic solution, I'm just ignorant about it, and would like to be educated as well :) – Mark Seemann Mar 17 '15 at 14:44

2 Answers2

20

The way you've proposed is entirely appropriate as a means of storing the state within the actor. The concurrency constraints of only processing 1 message at any time means that it's not possible to get into invalid states as a result of contention on a shared memory location.

However, it's not the most idiomatic option. Akka.Net provides an F# API to work with actors in a similar way to F# MailboxProcessors. In this case you define your actor as a tail recursive function which calls itself with some new state. Here's an example

spawn system "hello" <|
    fun mailbox ->
        let rec loop state =
            actor {
                let! msg = mailbox.Receive ()
                printfn "Received %A. Now received %s messages" msg state
                return! loop (state + 1) //Increment a counter for the number of times the actor has received a message
            }
        loop 0

For full documentation on the Akka.Net F# API see http://getakka.net/wiki/FSharp%20API

bruinbrown
  • 1,006
  • 2
  • 8
  • 13
10

There are two solutions, both of them use explicit recursive loop definition, main concept of Akka F# actors.

First you may define variables, which should be visible only inside actor's scope, before loop definition (in example below I've changed i definition to reference cell, because mutable variables cannot be captured by closures):

let actorRef =  
    spawn system "my-actor" <| fun mailbox ->
        let i = ref 1
        let rec loop () =
            actor {
                let! msg = mailbox.Receive()
                match msg with
                | Some x -> i := !i + x
                | None -> ()
                return! loop()
            }
        loop()

However, more advised solution is to keep your state immutable during message handling, and change it only when passing in next loop calls, just like this:

let actorRef = 
    spawn system "my-actor" <| fun mailbox -> 
        let rec loop i = 
            actor { 
                let! msg = mailbox.Receive()
                match msg with
                | Some x -> return! loop (i + x)
                | None -> return! loop i
            }
        loop 1  // invoke first call with initial state
Bartosz Sypytkowski
  • 7,463
  • 19
  • 36