FSharp and Akka.net - the functional way
Actor model is one of the most influential paradigms of dealing with highly concurrent environments in present world. Simplifying, it’s based on concept of autonomous thread-safe computation units – surprisingly called actors – with no way to directly interfere with each others work. There are no locks or semaphores – instead of accessing shared resources, they are simply passing messages around – according to the saying Don’t communicate by sharing memory; share memory by communicating.
The first most widespread usage of the actor model was the Erlang Virtual Machine in 1986. While it was for many years closed in it’s own niche, programming model itself has been lately forwarded and adopted on the Java Virtual Machine through Akka framework. Until present moment there are actually none mature equivalents on .NET platform. While Microsoft is still developing it’s own response in form of Project Orleans, a bunch of developers took the initiative of porting Akka on .NET ground.
I’ve decided to try out Akka.NET a little. I’ve noticed that it’s still a far from completion or production-ready phase, but hopefully since it’s based on already existing and mature framework, with help of OSS community missing holes could be patched soon.
Hello Akka
You can find an original first step into Akka.NET with F# API here. While I found this sample useful, I’ve decided to investigate more about Akka.NET source code and it’s F# API. Below you may see my example based on more functional-specific concepts:
type ActorMsg =
| Greet of string
| Hi
let system = System.create "MySystem" <| ConfigurationFactory.Default()
let greeter =
spawn system "Greeter"
<| fun mailbox ->
let rec loop() = actor {
let! msg = mailbox.Receive()
match msg with
| Greet name -> printfn "Hello %s" name
| Hi -> printfn "Hi"
return! loop() }
loop()
greeter <! Greet "Alex"
greeter <! Hi
Here are some explanations:
- We defined a discriminated union of messages
ActorMsg
, we want to respond to. - The next step is to create an
ActorSystem
, analogously to C# and original Scala versions. - We need to define and instantiate an
Actor
. However unlike the object approach – which required a custom actor type inheriting from one of the Akka actor classes and defining it’s own receiving method – here we define a tail recursive function, which uses anactor { ... }
computation expression instead of actor type declaration. - We pass that function through the lambda to
spawn
method, which attaches that behavior to our system and returns anActorRef
(not to be confused with Actor instance), assigned to ourgreeter
variable. This way we may refer to actors, and pass messages to them, even if they’re not present on our local machine (which is also one of the Akka use cases). - In the last to lines we simply send two messages to actor reference using tell operator
<!
.
As you can see, this piece of code is not directly translatable to C# or even Scala API equivalent. It’s much more Erlangish. We don’t have to define any classes and method overrides. Instead, we have a tail-recursive function. For me this seems more natural approach for F#, since it’s more functional-first language, while it’s syntax for object oriented programming is very verbose and ugly.